1.1. Definición de R
1.3. R vs. Rstudio
2.1. Paquetes y librerías
2.1.1. Concepto de función y vector
2.1.2. Uso de paquetes y librerías, exploración de funciones
2.2. La ayuda
2.4. Vectores
2.4.1. Concepto de vector y propiedades
2.4.2. Uso de vectores para obtener dataframes
2.4.3. Diferencia entre lista y vector
2.4.4. Operaciones básicas con vectores
2.5. Otro tipo de objetos
2.6. Recomendaciones de programación
2.6.1. Recomendaciones de programación y flujo de trabajo en R
2.6.2. Ejemplo completo
Trabajo reproducible: desde programación colaborativa a control de versiones
3.1. Obtención y tratamiento de datos: flujo de trabajo y tipos de datos
3.2. GitHub
Obtención y tratamiento aplicado a la ciencia de datos
4.1. Tidyverse
4.1.1. ¿Qué es tidyverse?
4.1.2. Resolución de un problema ambiental con tidyverse
4.2. Representación gráfica con ggplot
4.2.1. Tipos de gráficos
4.2.2. Sintaxis de ggplot
5.1. R como GIS
5.1.1. ¿Qué son los sistemas GIS o SIG?
5.1.2. Utilización de R como GIS
5.1.3. Ejemplos de su uso
5.1.4. Extracción de datos biológicos de la distribución de las especies a partir de GBIF
5.1.5. Extracción de información apartir de raster, uso del paquete raster
En este primer bloque nos familiarizamos con R y Rstudio.
R es un lenguaje de programación que en un principio fue creado para análisis estadístico, pero es mucho más que eso:
R es de código abierto (por lo que evoluciona constantemente adaptándose a las nuevas necesidades de los usuarios) y de libre acceso (por lo que todo el que quiera puede acceder a él, lo que ayuda a su evolución).
R ayuda al desarrollo del estado del arte al recopilar análisis y técnicas realizadas en código en investigaciones de un área de conocimiento concreta.
Es flexible y potente, pudiendo manejar bases de datos inmensas
Portátil y replicable en otras plataformas
En el existen ejemplos para casi cualquier análisis, sirviendo de guía o inspiración para nuevos investigadores
Todo es por y para la comunidad de forma que todas las mejoras de R van destinadas a suplir las necesidades de sus usuarios, y los usuarios tratan de hacer el código más accesible para los demás.
R, además, es muy versátil ya que en él existen una gran cantidad de paquetes, para la visualización, análisis y manipulación de datos.
R comparte muchas características con la ciencia:
Es gratuito
Es de código abierto
Es colaborativo
Con lo cual R se puede utilizar para investigaciones científicas, solo debemos asegurarnos de que las investigaciones sean replicables.
En cambio, Rstudio es un IDE (es decir, un entorno de desarrollo integrado (integrated development environment)) gratuito y en código abierto creado exclusivamente para R.
Así Rstudio no sería más que una interfaz de R , una “aplicación” que nos hace más sencillo trabajar con R.
Rstudio tiene las siguientes características:
Se produce un resaltado de la sintaxis, en ocasiones se autocompleta el código y la sangría se mantiene sola, estos aspectos ayudan al usuario a escribir un código más limpio y a escoger los términos correctos en cada ocasión.
Permite ejecutar el código directamente desde el editor del código fuente
Permite saltar rápidamente entre funciones definidas
Permite la colaboración
Presenta una potente autoría y una gran capacidad de depuración, de forma que es el propio Rstudio el que avisa de posibles errores en el código, permite generar documentos dinámicos, etc.
Al comparar el entorno de R y Rstudio observamos grandes diferencias:
La principal diferencia es que el entorno de R es mucho más sencillo que en Rstudio, en R podemos observar una barra de herramientas en la parte superior y la ventana principal de la consola y en caso de que abriésemos un script observaríamos la ventana de este. En cambio, en Rstudio el entorno es claramente más complejo, la barra de herramientas de la parte superior es mucho más compleja y diferenciamos hasta cuatro ventanas diferentes, una para los scripts, otra para la consola, otra para el ambiente de trabajo donde se reflejan las variables y datos guardados y una cuarta ventana donde se muestra la ayuda, gráficos e incluso los archivos del ordenador para abrirlos más fácilmente si fuese necesario, todas estas ventanas poseen diferentes pestañas por las que navegar.
Otra diferencia es la clave de colores que podemos observar en ambos entornos. En R solo hay dos colores, uno para el texto escrito con almohadillas (#), es decir, texto no ejecutable; y otro para el texto ejecutable. En cambio, en Rstudio existe un código de que colores que además de distinguir el texto ejecutable del no ejecutable diferencia entre los distintos caracteres (por ejemplo, los paréntesis, corchetes y flechas de asignación son de un color diferente al del resto del texto, y el texto entre comillas es de otro color diferente)
Otra diferencia importante es que en R no existen avisos de errores, o sugerencias de código, como sucede en Rstudio.
Simplemente al observar estas diferencias se pone de manifiesto que Rstudio facilita enormemente el trabajo con R.
R es un lenguaje de programación complejo que se asemeja al propio lenguaje humano y que va mucho más allá del análisis estadístico. Una razón para trabajar con R sería esta, ya que al ser un lenguaje que se asemeja al humano resulta más intuitivo de utilizar, a pesar de su inmensa complejidad.
Otra razón es que gracias a sus características permite desarrollar trabajos reproducibles a nivel científico.
En la actualidad se pretende fomentar el desarrollo de la ciencia reproducible, de forma que no solo el manuscrito sino también los datos y el código empleado estén disponibles a la comunidad científica, lo cual aceleraría el avance en el conocimiento.
A nivel académico la reproducibilidad es importante al facilitar la colaboración, la verificación y el avance en la ciencia.
Pero a nivel de las empresas también es importante ya que permite la reutilización del código lo que ahorra tiempo, por ejemplo.
Hemos realizado una exploración previa de R y Rstudio.
En R hemos realizado un ejemplo de una operación básica:
10e-78+10e-40
FALSE [1] 1e-39
En Rstudio hemos creado una variable e instalado un paquete:
a <- 45+7
install.packages("lattice", repos = "http://cran.us.r-project.org")
FALSE Installing package into 'C:/Users/tsuba/OneDrive/Documentos/R/win-library/4.1'
FALSE (as 'lib' is unspecified)
FALSE package 'lattice' successfully unpacked and MD5 sums checked
FALSE Warning: cannot remove prior installation of package 'lattice'
FALSE Warning in file.copy(savedcopy, lib, recursive = TRUE):
FALSE problem copying C:\Users\tsuba\OneDrive\Documentos\R\win-
FALSE library\4.1\00LOCK\lattice\libs\x64\lattice.dll to C:
FALSE \Users\tsuba\OneDrive\Documentos\R\win-library\4.1\lattice\libs\x64\lattice.dll:
FALSE Permission denied
FALSE Warning: restored 'lattice'
FALSE
FALSE The downloaded binary packages are in
FALSE C:\Users\tsuba\AppData\Local\Temp\RtmpQ9ItmP\downloaded_packages
library(lattice)
demo(lattice)
FALSE
FALSE
FALSE demo(lattice)
FALSE ---- ~~~~~~~
FALSE
FALSE > require(grid)
FALSE Loading required package: grid
FALSE
FALSE > old.prompt <- devAskNewPage(TRUE)
FALSE
FALSE > ## store current settings, to be restored later
FALSE > old.settings <- trellis.par.get()
FALSE
FALSE > ## changing settings to new 'theme'
FALSE > trellis.par.set(theme = col.whitebg())
FALSE
FALSE > ## simulated example, histogram and kernel density estimate superposed
FALSE > x <- rnorm(500)
FALSE
FALSE > densityplot(~x)
FALSE Error : The fig.showtext code chunk option must be TRUE
FALSE
FALSE > histogram(x, type = "density",
FALSE + panel = function(x, ...) {
FALSE + panel.histogram(x, ...)
FALSE + panel.densityplot(x, col = "brown", plot.points = FALSE)
FALSE + })
FALSE Error : The fig.showtext code chunk option must be TRUE
FALSE
FALSE > ## Using a custom panel function to superpose a fitted normal density
FALSE > ## on a Kernel Density Estimate
FALSE >
FALSE > densityplot( ~ height | voice.part, data = singer, layout = c(2, 4),
FALSE + xlab = "Height (inches)",
FALSE + ylab = "Kernel Density\n with Normal Fit",
FALSE + main = list("Estimated Density", cex = 1.4, col = "DarkOliveGreen"),
FALSE + panel = function(x, ...) {
FALSE + panel.densityplot(x, ...)
FALSE + panel.mathdensity(dmath = dnorm,
FALSE + args = list(mean=mean(x),sd=sd(x)))
FALSE + } )
FALSE Error : The fig.showtext code chunk option must be TRUE
FALSE
FALSE > ## user defined panel functions and fonts
FALSE >
FALSE > states <- data.frame(state.x77,
FALSE + state.name = dimnames(state.x77)[[1]],
FALSE + state.region = factor(state.region))
FALSE
FALSE > xyplot(Murder ~ Population | state.region, data = states,
FALSE + groups = state.name,
FALSE + panel = function(x, y, subscripts, groups)
FALSE + ltext(x = x, y = y, labels = groups[subscripts],
FALSE + cex=.9, fontfamily = "HersheySans", fontface = "italic"),
FALSE + par.strip.text = list(cex = 1.3, font = 4, col = "brown"),
FALSE + xlab = list("Estimated Population, July 1, 1975", font = 2),
FALSE + ylab = list("Murder Rate (per 100,000 population), 1976", font = 2),
FALSE + main = list("Murder Rates in US states", col = "brown", font = 4))
FALSE Error : The fig.showtext code chunk option must be TRUE
FALSE
FALSE > ##graphical parameters for xlab etc can also be changed permanently
FALSE > trellis.par.set(list(par.xlab.text = list(font = 2),
FALSE + par.ylab.text = list(font = 2),
FALSE + par.main.text = list(font = 4, col = "brown")))
FALSE
FALSE > ## Same with some multiple line text
FALSE > levels(states$state.region) <-
FALSE + c("Northeast", "South", "North\n Central", "West")
FALSE
FALSE > xyplot(Murder ~ Population | state.region, data = states,
FALSE + groups = as.character(state.name),
FALSE + panel = function(x, y, subscripts, groups)
FALSE + ltext(x = x, y = y, labels = groups[subscripts], srt = -50, col = "blue",
FALSE + cex=.9, fontfamily = "HersheySans"),
FALSE + par.strip.text = list(cex = 1.3, font = 4, col = "brown", lines = 2),
FALSE + xlab = "Estimated Population\nJuly 1, 1975",
FALSE + ylab = "Murder Rate \n(per 100,000 population)\n 1976",
FALSE + main = "Murder Rates in US states")
FALSE Error : The fig.showtext code chunk option must be TRUE
FALSE
FALSE > ##setting these back to their defaults
FALSE > trellis.par.set(list(par.xlab.text = list(font = 1),
FALSE + par.ylab.text = list(font = 1),
FALSE + par.main.text = list(font = 2, col = "black")))
FALSE
FALSE > ##levelplot
FALSE >
FALSE > levelplot(volcano, colorkey = list(space = "top"),
FALSE + sub = "Maunga Whau volcano", aspect = "iso")
FALSE Error : The fig.showtext code chunk option must be TRUE
FALSE
FALSE > ## wireframe
FALSE > wireframe(volcano, shade = TRUE,
FALSE + aspect = c(61/87, 0.4),
FALSE + screen = list(z = -120, x = -45),
FALSE + light.source = c(0,0,10), distance = .2,
FALSE + shade.colors.palette = function(irr, ref, height, w = .5)
FALSE + grey(w * irr + (1 - w) * (1 - (1-ref)^.4)))
FALSE Error : The fig.showtext code chunk option must be TRUE
FALSE
FALSE > ## 3-D surface parametrized on a 2-D grid
FALSE >
FALSE > n <- 50
FALSE
FALSE > tx <- matrix(seq(-pi, pi, length.out = 2*n), 2*n, n)
FALSE
FALSE > ty <- matrix(seq(-pi, pi, length.out = n) / 2, 2*n, n, byrow = T)
FALSE
FALSE > xx <- cos(tx) * cos(ty)
FALSE
FALSE > yy <- sin(tx) * cos(ty)
FALSE
FALSE > zz <- sin(ty)
FALSE
FALSE > zzz <- zz
FALSE
FALSE > zzz[,1:12 * 4] <- NA
FALSE
FALSE > wireframe(zzz ~ xx * yy, shade = TRUE, light.source = c(3,3,3))
FALSE Error : The fig.showtext code chunk option must be TRUE
FALSE
FALSE > ## Example with panel.superpose.
FALSE >
FALSE > xyplot(Petal.Length~Petal.Width, data = iris, groups=Species,
FALSE + panel = panel.superpose,
FALSE + type = c("p", "smooth"), span=.75,
FALSE + col.line = trellis.par.get("strip.background")$col,
FALSE + col.symbol = trellis.par.get("strip.shingle")$col,
FALSE + key = list(title = "Iris Data", x = .15, y=.85, corner = c(0,1),
FALSE + border = TRUE,
FALSE + points = list(col=trellis.par.get("strip.shingle")$col[1:3],
FALSE + pch = trellis.par.get("superpose.symbol")$pch[1:3],
FALSE + cex = trellis.par.get("superpose.symbol")$cex[1:3]
FALSE + ),
FALSE + text = list(levels(iris$Species))))
FALSE Error : The fig.showtext code chunk option must be TRUE
FALSE
FALSE > ## non-trivial strip function
FALSE >
FALSE > barchart(variety ~ yield | year * site, barley, origin = 0,
FALSE + layout = c(4, 3),
FALSE + between = list(x = c(0, 0.5, 0)),
FALSE + ## par.settings = list(clip = list(strip = "on")),
FALSE + strip =
FALSE + function(which.given,
FALSE + which.panel,
FALSE + factor.levels,
FALSE + bg = trellis.par.get("strip.background")$col[which.given],
FALSE + ...) {
FALSE + axis.line <- trellis.par.get("axis.line")
FALSE + pushViewport(viewport(clip = trellis.par.get("clip")$strip,
FALSE + name = trellis.vpname("strip")))
FALSE + if (which.given == 1)
FALSE + {
FALSE + grid.rect(x = .26, just = "right",
FALSE + name = trellis.grobname("fill", type="strip"),
FALSE + gp = gpar(fill = bg, col = "transparent"))
FALSE + ltext(factor.levels[which.panel[which.given]],
FALSE + x = .24, y = .5, adj = 1,
FALSE + name.type = "strip")
FALSE + }
FALSE + if (which.given == 2)
FALSE + {
FALSE + grid.rect(x = .26, just = "left",
FALSE + name = trellis.grobname("fill", type="strip"),
FALSE + gp = gpar(fill = bg, col = "transparent"))
FALSE + ltext(factor.levels[which.panel[which.given]],
FALSE + x = .28, y = .5, adj = 0,
FALSE + name.type = "strip")
FALSE + }
FALSE + upViewport()
FALSE + grid.rect(name = trellis.grobname("border", type="strip"),
FALSE + gp =
FALSE + gpar(col = axis.line$col,
FALSE + lty = axis.line$lty,
FALSE + lwd = axis.line$lwd,
FALSE + alpha = axis.line$alpha,
FALSE + fill = "transparent"))
FALSE + }, par.strip.text = list(lines = 0.4))
FALSE Error : The fig.showtext code chunk option must be TRUE
FALSE
FALSE > trellis.par.set(theme = old.settings, strict = 2)
FALSE
FALSE > devAskNewPage(old.prompt)
Hemos revisado conceptos básicos sobre R.
Una función reúne una serie de operaciones que se ejecutan como un todo, y que se pueden almacenar para usarlas cuando sea necesario siempre tiene una entrada y una salida.
Un vector es una consecución de números.
En clase hemos trabajado con diferentes funciones y hemos diferentes creado vectores para afianzar estos conceptos.
1+1
FALSE [1] 2
a= (1+1) # creación de un objeto
b <- 3+1 # es mejor nombrar con flechas (primero < y luego -)
c <- 4+2 # el shortcut es Alt + -
d<- c (1,2) # para construir un vector se hace con c (concatenar)
# y la serie de números que quieras entre paréntesis
#separados por coma.
sum(b) # sum es la función de suma, como vemos resume una operación
FALSE [1] 4
sum(d,c,b)
FALSE [1] 13
str (a) # esta función te permite ver la estructura del objeto
FALSE num 2
Un paquete y una librería son prácticamente lo mismo. Una librería o paquete es una consecución de funciones que nos permiten trabajar más fácilmente en R.
install.packages("tidyverse", repos = "http://cran.us.r-project.org")
FALSE Installing package into 'C:/Users/tsuba/OneDrive/Documentos/R/win-library/4.1'
FALSE (as 'lib' is unspecified)
FALSE package 'tidyverse' successfully unpacked and MD5 sums checked
FALSE
FALSE The downloaded binary packages are in
FALSE C:\Users\tsuba\AppData\Local\Temp\RtmpQ9ItmP\downloaded_packages
# con esta función se descargan e instalan paquetes
#el parámetro de "repos" se ha añadido posteriormente porque surgía un error, lo mismo ha sucedido con la instalación de ciertos paquetes
A pesar de haber instalado el paquete solo podremos usar sus
funciones si se lo indicamos a R, es decir, debemos llamar al paquete
para poder utilizar sus funciones, y para ello usamos al función
library, un símil para entenderlo podría ser entender la
función install.packages como comprar un libro en una
librería, mientras que la función library sería como coger
ese libro de la estantería para leerlo.
library(tidyverse) # para cargar librería
FALSE -- Attaching packages --------------------------------------- tidyverse 1.3.1 --
FALSE v ggplot2 3.3.5 v purrr 0.3.4
FALSE v tibble 3.1.6 v dplyr 1.0.8
FALSE v tidyr 1.2.0 v stringr 1.4.0
FALSE v readr 2.1.2 v forcats 0.5.1
FALSE -- Conflicts ------------------------------------------ tidyverse_conflicts() --
FALSE x dplyr::filter() masks stats::filter()
FALSE x dplyr::lag() masks stats::lag()
Instalamos y cargamos posteriormente la librería raster:
install.packages("raster", repos = "http://cran.us.r-project.org")
FALSE Installing package into 'C:/Users/tsuba/OneDrive/Documentos/R/win-library/4.1'
FALSE (as 'lib' is unspecified)
FALSE package 'raster' successfully unpacked and MD5 sums checked
FALSE
FALSE The downloaded binary packages are in
FALSE C:\Users\tsuba\AppData\Local\Temp\RtmpQ9ItmP\downloaded_packages
library (raster)
FALSE Loading required package: sp
FALSE
FALSE Attaching package: 'raster'
FALSE The following object is masked from 'package:dplyr':
FALSE
FALSE select
Un dataframe no es más que una tabla de datos, podemos tener datos cualitativos y cuantitativos, cada fila es una observación y las columnas son las variables.
Para explorar un dataframe podemos utilizar diferentes funciones:
names(iris) # para decirme las variables de este dato
FALSE [1] "Sepal.Length" "Sepal.Width" "Petal.Length" "Petal.Width" "Species"
str(iris) # me dice la estructura de esta variable
FALSE 'data.frame': 150 obs. of 5 variables:
FALSE $ Sepal.Length: num 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
FALSE $ Sepal.Width : num 3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
FALSE $ Petal.Length: num 1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
FALSE $ Petal.Width : num 0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
FALSE $ Species : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
petal <- select (iris, Petal.Width) # así me da error, porque
FALSE Error in (function (classes, fdef, mtable) : unable to find an inherited method for function 'select' for signature '"data.frame"'
# select es una función que sale en
# el paquete de raster y de tidyverse,
# le tengo que decir de quién quiero
# que lo use
Así para seleccionar que “select” queremos usar utilizaremos
dplyr que es un paquete que contiene funciones para la
manipulación de dataframes, al usar los :: indicamos que
queremos utilizar select de este paquete.
petal <- dplyr::select (iris, "Petal.Width")
Ahora vamos a quitar datos del dataframe.
nuevo2 <- dplyr::select (iris, - "Petal.Width")# para hacer cosas
# debemos nombrar la tabla
# y la variable que quiero
dim(iris) # dimensiones de tabla
FALSE [1] 150 5
nuevo <- 1:10
dim(nuevo) # Rstudio genera un warning si haces referencia a un objeto
FALSE NULL
# que no esta previamente definido en el script
También podemos eliminar columnas, a la hora de eliminar columnas existen varias formas de realizarlo, puede realizarse indicando la posición de la columna (lo cual es lo más habitual ya que es un proceso más rápido y cómodo) o bien puede realizarse indicando el nombre de la variable, lo cual es más reproducible, ya que independientemente de que cambiemos la posición de la columna siempre nos estaremos refiriendo a ella.
new <- iris[,-4] # quitas las cuarta columna
# Shorcut de corchetes en mi teclado, Alt gr + A0 (a con la o encima)
new <- iris[,-("Petal.Width")] #con nombre es más reproducible ya
FALSE Error in -("Petal.Width"): invalid argument to unary operator
# que la posición puede cambiar
new2 <- iris [,1:3]
new3 <- iris [,c(1:3)]# de estas dos maneras es correcto los : son los
# rangos, izquierda son filas y derecha columnas
new4 <- iris[1:10,1:3] # elijó las primeras 10 filas (observaciones),
# y las 3 primeras columnas
Cabe destacar que los rangos solo son válidos con posiciones, los nombres son carácteres y no los localiza, para hacerlo con nombres se tiene que escribir todos los nombres de esas columnas. Un ejemplo sería:
col_13 <- iris[1:10,1:3]
col_13_names <- iris[, c("Sepal.Length","Sepal.Width","Petal.Length")]
Dentro del dataframe podemos seleccionar columnas específicas
utilizando la siguiente estructura dataframe$variable1.
Con la función mean calculamos la media:
mean(col_13)# da error, porque col_13 es un dataframe no un vector,
FALSE Warning in mean.default(col_13): argument is not numeric or logical: returning
FALSE NA
FALSE [1] NA
# tiene 4 vectores
# na= son valores que desconoce, que no están disponibles
mean (col_13$"Petal.Lenght") # aquí estoy haciendo la media de una
FALSE Warning in mean.default(col_13$Petal.Lenght): argument is not numeric or
FALSE logical: returning NA
FALSE [1] NA
# variable o columna por lo que si funciona
Finalmente con la función data podemos cargar dataframes
aportados por los paquetes en el ambiente de trabajo:
data(iris)
Otros shorcuts interesantes son:
* Para poner sección es ctrl + shift + r
* Para guardar ctrl + s
La ayuda de Rstudio es un elemento sumamente práctico que nos permite encontrar información sobre las funciones y ejemplo de su uso.
Existen varias formas de usar la ayuda a través de la consola. Podemos usar una interrogación:
?mean # al ejecutarlo se abre una página donde se describe su
FALSE starting httpd help server ... done
# funcionamiento y se pone un ejemplo de cómo se utiliza
?? weighted.mean # busca las páginas de ayuda donde se menciona el
# término
help.search("weighted.mean") # realiza la misma función que ??
Podemos encontrar información sobre paquetes también:
help (package = "dplyr")
Además de las funciones str y summary que nos dan información sobre
una variable, podemos usar class para saber el tipo de
variable:
class (iris)
FALSE [1] "data.frame"
Si aún habiendo usado estas funciones sigues sin resolver tus problemas o dudas, puedes acudir a foros online para que otros usuarios te ayuden, pero para que te puedan ayudar debes crear un ejemplo reproducible.
Un ejemplo reproducible es un ejemplo del código que te esta dando problemas, que es simplificado, pero con todas las partes para que se reproduzca tu problema y con diferentes datos.
A este respecto, existen paquetes de R como reprex para generar estos ejemplos.
A la hora del directorio de trabajo existen varias funciones:
getwd() # para saber cual es nuestro directorio de trabajo
FALSE [1] "C:/Users/tsuba/OneDrive/Escritorio/MANUAL"
setwd() # para seleccionar el directorio de trabajo, de esta manera
FALSE Error in setwd(): argument "dir" is missing, with no default
# se selecciona el directorio en el que nos encontramos
#se puede hacer con la pestañita, pero mejor no , ya que si
# se hace en el script queda registrado
setwd("C:/Users/tsuba/OneDrive/Escritorio/MANUAL")
# Entre comillas y con barras
# SHORCUT DE MI TECLADO: para la barra al revés Alt gr + tecla de grados
Recomiendan trabajar con proyectos, cada proyecto lo suyo es que sea de un proyecto de análisis. Los proyectos son en realidad una “especie” carpeta de trabajo, es realmente una forma de organización.
La Pipa o %>% es un carácter que en el código me
indica dentro de..., un ejemplo sería:
iris%>%
dplyr::select (
"Species", "Sepal.Width", "Petal.Lenght")%>%
filter(iris [,1:3])
FALSE Error in `dplyr::select()`:
FALSE ! Can't subset columns that don't exist.
FALSE x Column `Petal.Lenght` doesn't exist.
# %>% funciona como el del $, pero con más cosas
Algunos usuarios por su propia comodidad generan sus propias
funciones, para crear una función se sigue la siguiente estructura
nombre <- function (dataframe, x=variable){df[,x]}
Donde las llaves indican lo que hacen las funciones
Importante: las funciones que creas aquí son tuyas, para que se hagan públicas las tienes que poner en github o publicar un paquete público de R.
La función select es para columnas, filter
hace los mismo pero para las observaciones o filas, se suele poner el
nombre de la variable.
En mi teclado las llaves se ponen con
Alt gr + A con dieresis
Un vector es conjunto de datos del mismo tipo, dispuestos en serie (uno detrás de otro), es una sola columna, una única variable, si es de una dimensión sería un escalar.
Los vectores presentan las siguientes propiedades o características:
- Tipo de dato, así los vectores pueden ser:
- Numéricos (pudiendo ser número enteros o dobles (decimales))
- Factor (pudiendo tener varios niveles)
- Carácteres
- De fecha
- Boleano (de unos y ceros / verdadero-falso)
- Tamaño/ longitud
- Atributos/metadatos adicionales
Con los vectores se pueden realizar operaciones básicas donde
+ se utiliza para sumas, - para restas,
* para multiplicación (en mi teclado es shift + tecla de
exponente), / para división y ^ para
exponentes (en mi teclado es shift + A con o).
Para averiguar las propiedades de un vector se pueden usar diferentes funciones.
Primero creamos un vector de altura:
altura <- c(1.65,1.70, 1.45, 1.56, 1.75)
Observamos sus propiedades:
typeof(altura) # Tipo
FALSE [1] "double"
length(altura) # Tamaño
FALSE [1] 5
# NOTA: el asistente inteligente puede salir automático o buscarlo con
# el tabulador y bajar con flechas para seleccionar
attributes(altura) # Atributo, NOTA: null indica que no hay nada que enseñar
FALSE NULL
Funciones que nos los enseñan todo serian:
str(altura) # Muestra el tipo y longitud
FALSE num [1:5] 1.65 1.7 1.45 1.56 1.75
summary(altura) # También nos muestra el tipo (en caso de una variable
FALSE Min. 1st Qu. Median Mean 3rd Qu. Max.
FALSE 1.450 1.560 1.650 1.622 1.700 1.750
# numérica calcula los percentiles y media, en una
# variable tipo caracter indica el tipo de dato y
# el tamaño o longitud del vector)
A continuación vamos a hacer una distribución normal de
media 1.70 y desviación estándar 0.15, para lo
cual debemos buscar la función adecuada y utilizamos la ayuda:
??norm # Sabemos que el término norm se usa para normal, así que
# buscamos todas las entradas con este término, al final vemos
# que en el paquete stats se menciona norm para una distribución
# normal y al pinchar vemos distintas funciones y las exploramos
?dnorm # un compañero comenta que puede ser esta, así que la exploramos,
# al explorarla vemos que no nos sirve
En realidad, la función adecuada es rnorm y es la que
usamos, ya que esta usa el número de observaciones, ya que
dnorm usa un vector de cuantiles.
altm <- rnorm (5, mean=1.74, sd=0.15) # Si no pongo mean y sd sigue
# funcionando igual por el orden
# de estos argumentos
altm <- rnorm (5, 1.74, 0.15) # Como es comentado funciona igual
Ahora con summary comparamos como se ajusta nuestro
vector a la distribución normal:
summary(altura)
FALSE Min. 1st Qu. Median Mean 3rd Qu. Max.
FALSE 1.450 1.560 1.650 1.622 1.700 1.750
summary(altm)
FALSE Min. 1st Qu. Median Mean 3rd Qu. Max.
FALSE 1.616 1.715 1.754 1.776 1.857 1.937
Al comparar observamos que nuestra media es menor a la media de la distribución normal, somos más bajitos.
Depende de la situación. Si tenemos que enseñar nuestro código a alguien o si tenemos pensado revisar el script más adelante, lo mejor es ponerlo, ya que la lectura es más sencilla y no tenemos que memorizar. En cambio, si es para algo rápido sobre lo que probablemente no volvamos a trabajar, lo mejor es no ponerlo, ya que nos ahorra tiempo.
Existen dos tipos de programación, una programación funcional y una programación orientada a objetos. La primera está más orientada a funciones, donde el usuario expresa lo que quiere hacer, haciendo que la programación sea más intuitiva y fácil de leer, R sería un lenguaje de programación funcional.
Ahora vamos a recordar cómo realizar gráficos y figuras y cómo
guardarlas. Para ello trabajaremos con los vectores que hemos creado
anteriormente sobre la altura (altura y
altm).
Algunas funciones para generar gráficos son:
plot(altura) # genera un gráfico de dispersión
FALSE Error : The fig.showtext code chunk option must be TRUE
boxplot(altura) # caja de bigotes
FALSE Error : The fig.showtext code chunk option must be TRUE
hist(altura) # histograma
FALSE Error : The fig.showtext code chunk option must be TRUE
Lo que queremos es generar una sola figura que contenga, un gráfico
de dispersión, una caja de bigotes y un histograma para las variables
altura y altm, y así poderlas comparar más
fácilmente.
Como queremos guardar dicha figura, lo primero que haremos será usar
la función tiff. Cabe mencionar que tiff es
una función que permite guardar una figura o imagen en formato tiff,
este es un formato del paquete raster, en el que definimos
la cantidad de píxeles por unidad de medida. Este código debe de
ejecutarse antes de la figura o imagen que deseamos guardar.
Para saber como funciona tiff utilizamos la ayuda y a
continuación lo usamos, también utilizaremos par para que
todas las figuras se ejecuten a la vez y nos salgan en la misma
imagen.
?tiff
x11() # añadido posteriormente ya que nos daba error, esto permite
# abrir una nueva ventana si te da error al ejecutar par
tiff(filename = "ejemplo",# aquí puedes eligir una subcarpeta poniendo
#la dirección
width = 100, height = 250, units = "mm",
res= 300) # si no pones comillas los caracteres se consideran
# objetos
?par
par(mfrow= c(3,2))# Aquí estamos definiendo la disposición que
# queremos,así definimos que queremos 3 filas
# con 2 columnas
# Aunque originalmente definimos 2 filas y 3
# columnas a mi parecer con esta disposición se
# entiende mejor.
plot(altura, # aquí con type podrías elegir el tipo de gráfico
# pero por defecto es un gráfico de puntos
col = "aquamarine4", # "col" define el color
ylab = "Altura (m)",
main = "Altura de clase", # "main" es el título
pch = 16 ) # "pch" define el tipo de punto,
FALSE Error : The fig.showtext code chunk option must be TRUE
# en total hay 25 tipos, el tamaño de los puntos
# también se puede cambiar con "cex"
plot(altm, col = "darkcyan", ylab = "Altura (m)",
main = "Altura de España", pch = 16)
FALSE Error : The fig.showtext code chunk option must be TRUE
boxplot(altura, main = "Altura de clase", col = "lightpink")
FALSE Error : The fig.showtext code chunk option must be TRUE
boxplot(altm, main = "Altura de España", col = "coral2" )
FALSE Error : The fig.showtext code chunk option must be TRUE
hist(altura, ylab = "Altura (m)", main = "Altura de clase",
col = "palegreen3")
FALSE Error : The fig.showtext code chunk option must be TRUE
hist(altm, ylab = "Altura (m)", main = "Altura de España",
col = "seagreen4")
FALSE Error : The fig.showtext code chunk option must be TRUE
dev.off() # para cerrar gráfico, y poder hacer otro nuevo
FALSE png
FALSE 2
# Tras ejecutar "dev.off" sale el mensaje de null device
Para guardar imágenes hay dos formatos posibles en formato vectorial y en formato foto.
A través de la repetición de los datos un vector podemos genera vectores de mayor tamaño.
altura <- c(1.65,1.70, 1.45, 1.56, 1.75)
altura2 <- rep(altura, 30) # Produce la repetición de los valores del
# vector altura, en este caso 30 veces
A continuación vamos a trabajar con otra variable, la variable
genero, donde anotaremos nuestro género en clase:
genero <- rep(c("mujer", "hombre"), c(3,2)) # con "rep" estamos
# consiguiendo repetir
# "mujer" 3 veces y
# "hombre" 2 veces
Pero hasta ahora la variable genero es considerada como
un vector de tipo carácter, pero para nosotros es un factor con 2
niveles o categorías nominales: mujer y hombre. Por ello, vamos a
trasformar la variable genero en un factor usando la
función as.factor:
genero_clase <- as.factor (genero)#como factor
Observamos las diferencias entre las variable genero y
genero_clase:
typeof(genero)
FALSE [1] "character"
str(genero)
FALSE chr [1:5] "mujer" "mujer" "mujer" "hombre" "hombre"
summary(genero)
FALSE Length Class Mode
FALSE 5 character character
typeof(genero_clase)
FALSE [1] "integer"
str(genero_clase)
FALSE Factor w/ 2 levels "hombre","mujer": 2 2 2 1 1
summary(genero_clase)
FALSE hombre mujer
FALSE 2 3
Para unir tablas estas deben tener datos del mismo tipo.
La función seq genera secuencias aleatorias de números
de una determinada cantidad de observaciones. En el ejemplo de abajo
definimos que queremos una secuencia de números entre el valor mínimo y
el valor máximo del vector altura, teniendo un total de 10000
observaciones.
seqalt <- seq( from =min(altura), to = max (altura),
length= 10000)
View(seqalt) # Ahora observamos el vector creado con esta función
# (primera letra en mayúsculas)
boxplot(seqalt, main= "Altura (muestra aleatoria)",
col = "cornflowerblue") # generamos un boxplot para visualizar
FALSE Error : The fig.showtext code chunk option must be TRUE
# más fácilmente los datos
Ahora procedemos a generar una matriz de datos a partir de este
vector númerico doble. Para ello, simplemente rompemos el vector
seqalt en una matriz de cuatro columnas usando la función
matrix:
?matrix # Para saber utilizar esta función consultamos a la ayuda
alt <- matrix(data= seqalt, nrow =100,
ncol=4, byrow=F) # Como defino el número de filas que
# quiero que tenga en realidad estoy
# acortando el dataframe
alt <- matrix(data= seqalt,
ncol=4, byrow=F) # Si quito el nrow, R es inteligente
# y me parte todo de la forma adecuada
# una matriz es un vector con
# dimensiones, entonces byrow me dice
# que me lo parte siguiendo filas o
# columnas, de forma default es
# columnas que es como se hace bien
# una matriz tiene el mismo numero de
# filas, es un dataframe no es
# una matriz
View(alt) # Observamos la matriz que hemos generado
A continuación vamos a realizar el dataframe completo:
Vamos a generar un dataframe compuesto por dos variables, por un ladO el dato numérico de la altura registrado, y por otro el rango de valores al que pertenece dicho valor.
En primer lugar, vamos a hacer un vector tipo factor o carácter que
me rompan en 3 partes iguales la muestra, los puntos de división que
vamos a establecer
son:X < cuantil 25,25 < x < 75 (entre
el cuantil 25 y el 75) y X > cuantil 75.
Para ello primero buscaremos los cuantiles:
quantile (seqalt)
FALSE 0% 25% 50% 75% 100%
FALSE 1.450 1.525 1.600 1.675 1.750
quantile( seqalt, 0.25)
FALSE 25%
FALSE 1.525
quantile(seqalt, 0.75)# estos cuantiles son mis puntos de corte
FALSE 75%
FALSE 1.675
Con los puntos de corte crearemos un vector en el que se definen los
intervalos en los que se dividirá el vector seqalt, este
nuevo vector se llama intervalos:
?cut
intervalos <- cut (seqalt, breaks= c(min(seqalt), # le pongo los puntos
# de mínimo, medio y
# máximo
quantile(seqalt, 0.25),
quantile(seqalt, 0.75),
max(seqalt)))
data <- data.frame (seqalt, intervalos)# puede ser así haciéndolo por
# separado o todo junto como
# abajo
data <- data.frame (seqalt,
kk=cut (seqalt, breaks= c(min(seqalt),
quantile(seqalt, 0.25),
quantile(seqalt, 0.75),
max(seqalt)),
labels = c("<0.25", "0.25-0.75", ">0.75")))
summary(data) # vemos un resumen del dataframe
FALSE seqalt kk
FALSE Min. :1.450 <0.25 :2499
FALSE 1st Qu.:1.525 0.25-0.75:5000
FALSE Median :1.600 >0.75 :2500
FALSE Mean :1.600 NA's : 1
FALSE 3rd Qu.:1.675
FALSE Max. :1.750
boxplot(data$seqalt~data$kk,
col = "coral1") # representamos los datos de cada intervalo
FALSE Error : The fig.showtext code chunk option must be TRUE
# el primero es la y , y el segundo es la x
La principal diferencia entre un vector y una lista, es que un vector es una serie de datos del mismo tipo, mientras que una lista puedeestar compuesta por elementos de distinto tipo.
NOTA: El shortcut para ir al paréntesis correspondiente Ctrl + p
Hay numerosas funciones que podemos usar:
log(x): logaritmo natural
exp(x): exponencial
max(x): máximo
min(x): mínimo
round(x,n): redondear decimales
cor(x): correlación
sum(x): suma
mean(x): media
median(x): mediana
quantile(x): cuantil
rank(x): ranking de elementos
var(x): varianza
sd(x): desviación estándar
> : mayor que
< : menor que
> = : mayor o igual que
< = : menor o igual que
= = : exactamente igual a
! = : No igual a
! : lógico NO
&: lógico Y
| : lógico O (ctrl + 1)
&& : Y con IF
|| : O con IF
%in% : que contiene
Además de vectores, existen otro objetos que almacenan información y con los que ya hemos trabajado.
Están las matrices, las matrices son vectores con atributos de dimensión, es decir, se trata de un objeto homogéneo (formado por un mismo tipo de dato, como un vector)y formado por dos dimensiones (observaciones y variables, es decir, filas y columnas, los vectores están formados únicamente por observaciones, son una fila)
También encontramos listas, un objeto formado por una dimensión (solo observaciones) y de datos diferentes (heterogéneos).
Por último, están los dataframes, que son objetos heterogéneos (formado por diferentes tipos de datos) con 2 dimensiones (filas y columnas).
Estos tipos de objetos se pueden interconvertir entre ellos, a través de diferentes funciones:
De vector a un vector más largo: c(x,y)
De matriz a vector: as.vector(mymatrix)
De vector a matriz: cbind(x,y),
rbind(x,y)
De dataframe a matriz: as.matrix(myframe)
De vector a dataframe: data.frame(x,y)
De matriz a dataframe:
as.data.frame(mymatrix)
En este apartado vamos a ver recomendaciones para la escritura del código.
1). Comprobar que en global options no esté marcado
R restore data, ya que si se restaura, al trabajar con
datos muy grandes hace que tarde más en abrirse Rstudio.
2). Generar un proyecto organizado, ¿Cómo?:
Generando carpetas para los tipos de archivos, por ejemplo:
una carpeta para los scripts
una carpeta de output (figuras, tablas y resultados)
una carpeta de informe (con un rmarkdown)
Se pueden numerar las carpetas para que sigan un orden lógico en el que los usarías o generarías. En m,i caso yo realizaría primero la carpeta de scripts, posteriormente, datos, resultados y finalmente el informe; en cambio la profesora seguiría el orden de primero los datos, segundo scripts, despues resultados y finalmente informe. La creación de una gran cantidad de subcarpetas supone un problema y es que el directorio de trabajo se tendría que cambiar más veces, ya que tienes que especificar esas subcarpetas en el directorio de trabajo (directorio de trabajo es el sitio donde se guarda el script).
Nombres de los archivos, asegurandonos de elegir
un nombre que sea memorable (fácil de recordar) y que nos ayude a
identificar el contenido o tipo de archivo. A.EJEMPLO: ¿Qué nombre es el
más correcto para un script que ajusta modelos? 1.
ajuste-modeloR 2. a-modR El mejor sería el
primero ya que es completo y fácil de recordar, el segundo, pasado un
tiempo ya no te acuerdas.
3). El código debe tener una buena sintaxis y que sea fácil de leer:
Documenta el código/ comenta el código para que los demás lo entiendan o lo entiendas tu tiempo después. No hay que comentar todo, decirlo de forma resumida y que tenga estructura.
Usar nombres memorable y correctos:para que nombres sean
correctos hay que tener en cuenta que r es sensible a mayúscula y
minúscula. Las palabras deben de estar separadas por un guión bajo, y
asignar nombres claros. EJEMPLO ¿Cuál sería correcta? 1.
mi_vector -> correcto 2. MiVector 3.
vector.1
Una revista científica recoge artículos de revisión, investigación, etc; que mantiene un formato concreto.
Todas las publicaciones científicas están revisadas. Las fuentes fiables de información muestran datos como: autores, revista, editor, etc. Se pueden citar y referenciar conocimiento previo, metodologías y bases de datos. También se debe citar el software y paquete usado. Las citas textuales solo se pone apellido y año.
Un repositorio es un sitio web donde se almacenan muchos datos.
¿Cómo buscar información en estos?: Podemos buscar información de muchas maneras, en bases de datos, usando palabras clave, buscando a un autor específico, etc.
Algunas bases de datos son easy web of knowdelge y scopus, incluso en buscadores como google scholar.
A la hora de buscar un artículo, el criterio para seleccionar los artículos más relevantes es guiarse por:
Mayor número de citas
Filtrar el área de conocimiento del artículo para escoger artículos de áreas relevantes en nuestro estudio
Intentar seleccionar artículos de revisión, ya que resumen el conocimiento actual sobre el tema
Escoger artículos recientes ya que tratan los últimos descubrimientos del tema
Si encontramos un artículo que nos inspire debemos guardarlo, ya que puede resultar útil para investigaciones futuras.
Para escribir un documento lo más apropiado es un tema, un párrafo. Debemos pensar estructura y nombres para nuestro proyecto de prácticas.
Poner espacio después de la coma, no antes:
x[, 1] -> SÍ x[,1] -> NO
Sin espacio antes/ paréntesis: mean(x, na.rm = T)
mean (x, na.rm = T) ¿Por qué? pues porque
son los argumentos de la función es como si fuese una palabra, por ello
no se pone espacio.
Antes y después de una flecha de asignación, = , tabulación, etc;
deja un espacio, ayuda a leer. a <- 1
a<-1
Corregir sintaxis del manual, la tabulación son los espacios que quedan al escribir entre varias lineas:
a1 <- c(1,
2,
3)
# estos espacios
4). Estructura el código y piensa las secciones:
Ejemplos de secciones:
Directorio de trabajo (si no fuese un proyecto)
Instalación los paquetes y librerías que vayas a usar (al principio)
Cargar datos
Analizar los datos
Obtener y guardar los resultados
¿Para qué usarías nombre y verbo?
El nombre para variables y el verbo para resultados de una función. Consejo: evitar nombres que sean comunes de funciones y variables Para ampliar estas recomendaciones mira en la página web: https://style.tidyverse.org/
¿Qué es mejor hacer un script único con secciones o con varios script?
En principio si esta organizado da igual, si se rompe y los script Deben ejecutarse secuencialmente, deben numerarse para evitar errores.
NOTA : tabulación es la tecla encima de mayúsculas (flechitas) y alt+ tabulación permite pasar entre ventanas.
Cada archivo tiene una determinada extensión y la extensión me indica el tipo de archivo: - txt es separado por / # es un texto plano - csv es separado por , - xls pueden tener diferentes hojas para unos datos determinados - access es mdb es como un punto mas que excel - excel tiene varios problemas, por ejemplo, un nº limitado de columnas
Git es como hacer proyectos, pero en vez de tenerlo en el programa lo tienes en la nube, así tienes control de versiones mucho más fácilmente, además de que se puede compartir.
Para poner en práctica todas estas recomendaciones realizaremos un ejemplo completo. En este ejemplo vamos a seguir el hilo de mi práctica y realizaremos un estudio de la biodiversidad de aves según tipo de uso del suelo.
Aquí vamos a usar la librería dplyr y
ggplot2, en caso de no estar instaladas las debemos
instalar:
install.packages(c("dplyr", "ggplot2"), dep=T)
FALSE Warning: packages 'dplyr', 'ggplot2' are in use and will not be installed
#dep, es dependencies and construction, significa que te instalará
#y descargará lo que le haga falta para los paquetes
library("dplyr") # lo llamas
Generamos un dataframe con datos aleatorios:
x <- data.frame(id = seq(from = 1, to =100),
uso = rep(c("A", "B"), times = 50),
riqueza = rnorm (100, mean = 3, sd = .5))
? write.csv
write.csv(x, file= "C:/Users/tsuba/OneDrive/Escritorio/MANUAL/1-datos brutos/diversidad_usos.csv")
# Guardamos el dataframe como un csv, en la dirección se debe cambiar la posición de la barra.
Ahora leemos el dataframe (lo cargamos):
?read.csv
datos <- read.csv("C:/Users/tsuba/OneDrive/Escritorio/MANUAL/1-datos brutos/diversidad_usos.csv")
View (datos)
Al observar los datos vemos que se ha generado una nueva columna, esta columna llamada X se corresponde con datos id que se han generado automáticamente en la tabla.
Vemos las características del dataframe:
str(datos) # la mejor forma
FALSE 'data.frame': 100 obs. of 4 variables:
FALSE $ X : int 1 2 3 4 5 6 7 8 9 10 ...
FALSE $ id : int 1 2 3 4 5 6 7 8 9 10 ...
FALSE $ uso : chr "A" "B" "A" "B" ...
FALSE $ riqueza: num 2.54 3.92 3.31 3.35 3.04 ...
summary (datos) # te indica hasta los NA (sin datos)
FALSE X id uso riqueza
FALSE Min. : 1.00 Min. : 1.00 Length:100 Min. :1.821
FALSE 1st Qu.: 25.75 1st Qu.: 25.75 Class :character 1st Qu.:2.733
FALSE Median : 50.50 Median : 50.50 Mode :character Median :3.011
FALSE Mean : 50.50 Mean : 50.50 Mean :3.021
FALSE 3rd Qu.: 75.25 3rd Qu.: 75.25 3rd Qu.:3.354
FALSE Max. :100.00 Max. :100.00 Max. :3.925
¿Cómo podemos quitar la columna autogenerada que
sobra?, para ello usaremos el código de abajo, donde
- resta una columna.
datos1 <- datos[,-1] # quito la primera columna que es un
# autonumérico
A continuación vamos a analizar nuestro dataframe, donde Haremos la media y sd (desviación típica) de riqueza, para cada nivel del uso del suelo.
names (datos1) # para saber mis variables
FALSE [1] "id" "uso" "riqueza"
mean(datos1$riqueza)
FALSE [1] 3.020719
Podemos usar tapply(), esta agrupa los datos de un
vector de acuerdo a otra variable categórica y una función.
Quiero ver la media de la riqueza en función del uso del suelo:
summary(datos1$uso) # me lo considera como algo lineal, entonces
FALSE Length Class Mode
FALSE 100 character character
# me da error el tapply
summary(as.factor(datos1$uso)) # ahora que lo veo como factor
FALSE A B
FALSE 50 50
# y si me lo coge
medaves <- tapply(datos1$riqueza, datos1$uso, FUN = mean)
sdaves<- tapply(datos1$riqueza, datos1$uso, FUN = sd) # todo esto
# hay que ir # guardándolo # en carpetas # específicas
resumen_aves <- data.frame (medaves, sdaves)
write.csv(resumen_aves, "C:/Users/tsuba/OneDrive/Escritorio/MANUAL/1-datos brutos/resumen_aves.csv")
Finalmente haremos un boxplot de riqueza en función del suelo A y B y lo guardaremos en una carpeta de resultados.
?boxplot
tiff(filename = "C:/Users/tsuba/OneDrive/Escritorio/MANUAL/1-datos brutos/plot_aves.tiff",
width= 700,height = 100, units="mm", res = 300 )
aves <- boxplot(riqueza ~ uso, data= datos1,
xlab = "Usos del suelo",
ylab = "riqueza de aves", col = "indianred2")
FALSE Error : The fig.showtext code chunk option must be TRUE
En este apartado hablaremos sobre flujo de trabajo, tipos de datos, github y Rmarkdown, centrándonos especialmente en los archivos rmd.
A la hora de trabajar debemos seguir siempre un flujo de trabajo donde:
1.Partimos de una pregunta o problema
2.Plantearnos que datos necesitamos usar y donde los podemos conseguir
3.Trabajar con los datos donde:limpieza, análisis y visualización
4.Mostrar los resultados
¿Y qué son los datos?
No son más que una colección de: hechos, observaciones, medidas, etc.
Tipos de datos
Existen muchas clasificaciones diferentes dependiendo de la aproximación que sigamos:
Datos cuantitativos y cualitativos
Datos crudos y procesados
En función del soporte: analógico, digital, vídeo-audio, etc.
En función de su formato: tablas, vectores, matrices, mapas, etc.
En función de sus dimensiones:
Vector: 1 dimensión
Matriz: 2 dimensiones (se pueden organizar en dataframes o en tibble)
Arreglos: varias dimensiones
Listas
En función de la temática: geográficos, estadísticos, científicos, financieros, meteorológicos, etc.
Los archivos que contienen los datos pueden tener extensiones muy diferentes, por ejemplo: txt, pdf, tiff, xml, csv, etc.
Hay enlaces a muchos repositorios en la presentación de obtención y tratamiento de datos, revisa la presentación…
Es una plataforma online donde se comparte código de R entre desarrolladores, cualquier usuario tiene acceso a los códigos y paquetes publicados en esta plataforma, y puede crear sus propios repositorios. Además, github también permite establecer un control de versiones en los proyectos de forma que ayuda a que los trabajos sean más reproducibles.
De manera que esta plataforma permite que el trabajo con R sea más colaborativo y reproducible, además de ayudar al desarrollo de R como lenguaje de programación.
En este aspecto Git es un sistema de control de versiones abierto que funciona como el control de cambios de Word. Mientras que GitHub funciona a modo de almacén para nuestros proyectos en internet. Git y GitHub fueron creados en un principio para grupos de programadores pero se puede aplicar a cualquier grupo de trabajo.
¿Por qué usar un control de versiones?
Porque todos los cambios se quedan almacenados permitiéndonos volver a versiones anteriores del documento y recuperar cualquier elemento de una versión anterior. Además, también se registra quién realizó los cambios, en qué fecha y por qué, de manera que facilita el trabajo en grupo.
Los repositorios permiten almacenar documentos y proyectos en GitHub, y pueden ser tanto públicos (donde cualquier usuario puede acceder) o privado.
Los repositorios se organizan en ramas o “branches”, donde cada rama permite un desarrollo de trabajo diferente a mi entender, las ramas funcionan a modo de subcarpetas, tenemos una rama principal (“main”), donde se trabaja con el proyecto. Se pueden generar ramas independientes (otras carpetas), donde se este trabajando con otros proyectos distintos o con partes diferentes del proyecto, y posteriormente estas ramas pueden fusionarse con la principal (meter una carpeta dentro de otra).
Las nuevas ramas se generan por medio de los “pull and request”.
El apartado de issues funciona a modo de un foro, donde una persona abre un “issue” o tema para preguntar algo o para pedir ayuda, y las personas que tienen compartido ese repositorio pueden acceder a ese “issue” y tratar de responder a la duda o resolver el problema concreto.
Los archivos rmd son un tipo de documentos con una extensión propia de rmarkdown que actúan como intermediarios entre un script y un output definitivo, por ejemplo un archivo html.
En un archivo rmd tenemos dos elementos principales, código ejecutable o chunk, el cual se engloba en una especie de recuadro ejecutable; y un elemento de texto que no es ejecutable y que funciona de la misma manera que un procesador de texto. Al inicio del archivo rmd existe un cuadro de opciones (que se conoce como Yaml, Yaml header o preámbulo; y se escribe en lenguaje Yaml), donde se pueden definir aspectos del output, como por ejemplo el tipo de documento que se generará (pdf, html, word, etc) e incluso se pueden definir parámetros estéticos, como el tipo y color de letra en temas personalizados.
Cuando un archivo rmd se “teje” o “knit” (es un compilador, es decir, compila una serie de instrucciones y las traduce a otro lenguaje como puede ser html) se genera el output final definido en el Yaml. En el output se ejecutan todos los chunks (código) y el texto adquiere un formato concreto que se define en el documento rmd, donde, por ejemplo, el número almohadillas (#) al inicio del texto define el tamaño de los títulos.
En este bloque hemos estado trabajando directamente sobre un archivo rmd.
Con rmarkdown también se pueden crear presentaciones powerpoint y archivos shiny (que se caracterizan por ser documentos dinámicos e interactivos).
Sobre Rmarkdown
Rmarkdown es un lenguaje de marcado (al igual que lo es html, no es un lenguaje de programación). Rmarkdown carece de funciones aritméticas. Un lenguaje de marcado es un lenguaje con marcas y etiquetas que sirven de dictado para que un software siga unas determinadas especificaciones.
A lo largo de este bloque aprenderemos a manejar los datos y a
visualizarlos por medio de diferentes tipos de gráficos. En este bloque
trabajaremos mayoritariamente con el paquete ggplotde
tidyverse.
tidyverse es una colección de paquetes de R que engloba
un total de 8 paquetes con funciones diferentes:
readr: que se utiliza para leer datos
dplyr: para la manipulación de datos
tibble
tidyr
purrr
stringr
forcats
ggplot2: para la visualización de datos
Con tidyverse se pueden realizar todas las funciones de
rbase (que es el conjunto de funciones que vienen
preinstaladas al descargar R), pero de forma más intuitiva y
simplificada. La gran ventaja del uso de tidyverse, aparte
de que simplifica enormemente el código, es que todos los paquetes que
contiene y todas las funciones de dichos paquetes tienen una sintaxis
similar (haciendo que la nomenclatura sea consistente), lo cual hace que
sea mucho más intuitivo y sencillo de utilizar que
rbase.
Por lo general la sintaxis de tidyverse se caracteriza
por utilizar “_” en vez de “.”
Otras ventajas con respecto rbase son que las funciones
de tidyverse son mucho más rápidas que las de
rbase, añade automáticamente los formatos de fecha y
tiempo, y que muestra una barra de carga para mostrar el estado de carga
de los datos.
Aquí vamos a centrarnos en el trabajo con dplyr.
A lo largo de esta clase vamos a intentar resolver un problema ambiental, pero antes de comenzar vamos a cargar varias librerías:
library(here)
FALSE here() starts at C:/Users/tsuba/OneDrive/Escritorio/MANUAL
library(patchwork)
FALSE
FALSE Attaching package: 'patchwork'
FALSE The following object is masked from 'package:raster':
FALSE
FALSE area
library(viridis)
FALSE Loading required package: viridisLite
library(ggpmisc)
FALSE Loading required package: ggpp
FALSE
FALSE Attaching package: 'ggpp'
FALSE The following object is masked from 'package:ggplot2':
FALSE
FALSE annotate
library(tidyverse)# Al cargar este paquete nos salen conflictos, esto se debe a
# que funciones de un paquete están enmascaradas por funciones
# de otro paquete, simplemente a la hora de usar dichas funciones
# debemos tener en cuenta de que paquete la queremos utilizar y definirlo
El problema ambiental a resolver es el siguiente:
En el ayuntamiento de Alcalá de Henares Hay discrepancias entre los políticos sobre la influencia del ser humano en el cambio climático. Algunos piensan que el cambio climático no existe, otros piensan que el cambio climático si existe pero que no se debe a la influencia humana y otros piensan que el sr humano si influye en el cambio climático, ya que existen innumerables evidencias científicas que lo corroboran.
Para resolver este problema hemos necesitado los siguientes datos:
Datos climáticos sobre Alcalá: https://verughub.github.io/easyclimate/index.html
Datos sobre las emisiones de CO2 en España: https://edgar.jrc.ec.europa.eu/report_2020#data_download
Para resolver este problema ambiental trabajaremos con todos y cada
uno de los paquetes de tidyverse.
El planteamiento para resolverlo es el siguiente:
Vamos a representar comoa medida que aumenta el CO2 aumenta la temperatura, de esta manera el CO2 es la variable independiente y temperatura es la dependiente. De esta manera mostramos que existe el cambio climático.
Para evidenciar el efecto del ser humano en el cambio climático podemos ver como varían la temperatura y niveles de CO2 con el tiempo y luego disgregar los datos de CO2 en sectores para ver su origen.
Antes de comenzar a utilizar tidyverse debemos descargar
los datos climáticos y de CO2 para Alcalá de Henares, para
esto utilizaremos el paquete easyclimate:
Primero debemos instalar el paquete.
install.packages("easyclimate")# no podemos, porque no esta en el cran, que es donde
FALSE Installing package into 'C:/Users/tsuba/OneDrive/Documentos/R/win-library/4.1'
FALSE (as 'lib' is unspecified)
FALSE Error in contrib.url(repos, "source"): trying to use CRAN without setting a mirror
# están las librerías oficiales de R, por eso tenemos
# que instalarlo con remotes
install.packages("remotes")# como carecíamos de este paquete lo hemos tenido que instalar
FALSE Installing package into 'C:/Users/tsuba/OneDrive/Documentos/R/win-library/4.1'
FALSE (as 'lib' is unspecified)
FALSE Error in contrib.url(repos, "source"): trying to use CRAN without setting a mirror
remotes::install_github("VeruGHub/easyclimate")# así es como se instala, entre comillas
FALSE Skipping install of 'easyclimate' from a github remote, the SHA1 (b66c099f) has not changed since last install.
FALSE Use `force = TRUE` to force installation
# es la dirección del repositorio de
# Github donde se encuentra
Cargamos la librería easylimate.
library(easyclimate)
Definimos las coordenadas de la región de donde queremos descargarnos los datos.
coords <- data.frame(
lon = -3.35,
lat = 40.48
)
Se representa un mapa, aunque esto no lo hemos realizado en clase, y esto simplemente nos señala en un mapa la posición de Alcalá de Henares.
ggplot() +
borders(regions = c("Spain", "Portugal", "France")) +
geom_point(data = coords, aes(x = lon, y = lat)) +
coord_fixed(xlim = c(-10, 2), ylim = c(36, 44), ratio = 1.3) +
xlab("Longitude") +
ylab("Latitude") +
theme_bw()
FALSE Error : The fig.showtext code chunk option must be TRUE
Con este código descargaríamos los datos de temperatura de Alcalá de
Henares con el paquete easyclimate, no ejecutamos este
código porque estos datos de temperatura y los datos de CO2 ya los
tenemos descargados.
# temp <- get_daily_climate(
# coords,
# period = 1950:2020,
# climatic_var = c("Tmin", "Tmax")
# )
# save(temp, file = "00-raw/temp.RData")
# load(here("00-raw", "temp.RData"))
Este paquete nos permite cargar datos.
Comenzamos cargando los datos de CO2
A la hora de cargar los datos hemos visto varios errores, que hemos ido resolviendo sobre la marcha.
# En primer lugar hemos trabajado con el paquete de rbase
co_data <- read.csv("intro_tidyverse-dplyr-main/01-data/co2.csv")
# Cuando estábamos trabajando en clase no lo encontraba, porque el archivo rmd
# en el que trabajamos estaba en otra carpeta diferente a la de datos
# Para resolverlo en clase usamos ".." que indica que salimos de la carpeta donde
# nos encontramos con el rmd.
# Posteriormente hemos pasado a trabajar con tidyverse.
# Con tidyverse podemos utilizar el paquete here, que nos facilita mucho el trabajo
here()
FALSE [1] "C:/Users/tsuba/OneDrive/Escritorio/MANUAL"
co_data <- read_csv(here("intro_tidyverse-dplyr-main", "01-data", "co2.csv"))# pongo "," porque en el paquete here se especifica así, además al poner el guión bajo estoy usando la función read del paquete readr de tidyverse
FALSE Rows: 1036 Columns: 52
FALSE -- Column specification --------------------------------------------------------
FALSE Delimiter: ","
FALSE chr (52): Sector, country_name, 1970, 1971, 1972, 1973, 1974, 1975, 1976, 19...
FALSE
FALSE i Use `spec()` to retrieve the full column specification for this data.
FALSE i Specify the column types or set `show_col_types = FALSE` to quiet this message.
Aquí hemos utilizado la función read_delim donde tu
marcas el elemento que delimita los datos en vez de utilizar
read_csv:
temp <- read_delim (here("intro_tidyverse-dplyr-main", "01-data", "temalcala.csv"), delim =";")
FALSE Rows: 25933 Columns: 6
FALSE -- Column specification --------------------------------------------------------
FALSE Delimiter: ";"
FALSE dbl (5): ID_coords, lon, lat, Tmin, Tmax
FALSE date (1): date
FALSE
FALSE i Use `spec()` to retrieve the full column specification for this data.
FALSE i Specify the column types or set `show_col_types = FALSE` to quiet this message.
read de
rbase y la de tidyverse?La principal diferencia es que esta función en tidyverse
es mucho más rápida que con rbase, pero al mismo tiempo es
más exigente con el código utilizado dando errores muchas más veces pero
ayudando a mejorar tu código al mismo tiempo. También puede dar
problemas con tildes, y sale una barra de progreso de carga de los
datos.
Tras cargar los datos realizamos una exploración de los mismos.
Para la exploración de los datos usamos str y
summary.
str(co_data)
FALSE spec_tbl_df [1,036 x 52] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
FALSE $ Sector : chr [1:1036] "Buildings" "Buildings" "Buildings" "Buildings" ...
FALSE $ country_name: chr [1:1036] "Afghanistan" "Albania" "Algeria" "Angola" ...
FALSE $ 1970 : chr [1:1036] "0.58" "0.99" "1.81" "0.12" ...
FALSE $ 1971 : chr [1:1036] "0.58" "0.99" "1.81" "0.12" ...
FALSE $ 1972 : chr [1:1036] "0.46" "1.10" "2.11" "0.14" ...
FALSE $ 1973 : chr [1:1036] "0.57" "1.30" "2.51" "0.14" ...
FALSE $ 1974 : chr [1:1036] "0.77" "1.41" "2.68" "0.13" ...
FALSE $ 1975 : chr [1:1036] "0.59" "1.75" "2.97" "0.12" ...
FALSE $ 1976 : chr [1:1036] "0.48" "1.91" "3.79" "0.09" ...
FALSE $ 1977 : chr [1:1036] "0.43" "2.02" "3.80" "0.10" ...
FALSE $ 1978 : chr [1:1036] "0.41" "2.21" "4.46" "0.33" ...
FALSE $ 1979 : chr [1:1036] "0.48" "2.69" "5.16" "0.56" ...
FALSE $ 1980 : chr [1:1036] "0.45" "1.73" "5.37" "0.70" ...
FALSE $ 1981 : chr [1:1036] "0.52" "1.81" "5.84" "0.66" ...
FALSE $ 1982 : chr [1:1036] "0.60" "1.90" "6.24" "0.38" ...
FALSE $ 1983 : chr [1:1036] "0.94" "2.01" "7.04" "0.50" ...
FALSE $ 1984 : chr [1:1036] "0.99" "2.06" "7.76" "0.55" ...
FALSE $ 1985 : chr [1:1036] "1.28" "2.09" "4.87" "0.60" ...
FALSE $ 1986 : chr [1:1036] "1.20" "2.20" "5.60" "0.62" ...
FALSE $ 1987 : chr [1:1036] "0.79" "2.20" "6.01" "0.63" ...
FALSE $ 1988 : chr [1:1036] "0.85" "2.33" "6.03" "0.75" ...
FALSE $ 1989 : chr [1:1036] "0.98" "1.53" "6.76" "0.73" ...
FALSE $ 1990 : chr [1:1036] "1.04" "2.09" "6.59" "0.66" ...
FALSE $ 1991 : chr [1:1036] "0.99" "1.32" "7.54" "0.69" ...
FALSE $ 1992 : chr [1:1036] "0.69" "0.57" "7.78" "0.62" ...
FALSE $ 1993 : chr [1:1036] "0.60" "0.39" "8.23" "0.51" ...
FALSE $ 1994 : chr [1:1036] "0.63" "0.33" "8.17" "0.63" ...
FALSE $ 1995 : chr [1:1036] "0.36" "0.33" "8.09" "0.67" ...
FALSE $ 1996 : chr [1:1036] "0.33" "0.45" "8.31" "0.91" ...
FALSE $ 1997 : chr [1:1036] "0.36" "0.38" "7.98" "0.91" ...
FALSE $ 1998 : chr [1:1036] "0.29" "0.29" "8.63" "1.01" ...
FALSE $ 1999 : chr [1:1036] "0.29" "0.75" "9.09" "1.26" ...
FALSE $ 2000 : chr [1:1036] "0.21" "0.76" "9.33" "1.05" ...
FALSE $ 2001 : chr [1:1036] "0.12" "0.80" "9.53" "1.17" ...
FALSE $ 2002 : chr [1:1036] "0.05" "1.17" "9.89" "1.20" ...
FALSE $ 2003 : chr [1:1036] "0.03" "1.04" "10.68" "1.26" ...
FALSE $ 2004 : chr [1:1036] "0.04" "0.88" "11.51" "1.30" ...
FALSE $ 2005 : chr [1:1036] "0.08" "0.70" "12.50" "1.00" ...
FALSE $ 2006 : chr [1:1036] "0.11" "0.93" "12.19" "1.96" ...
FALSE $ 2007 : chr [1:1036] "0.16" "0.72" "13.60" "2.33" ...
FALSE $ 2008 : chr [1:1036] "0.32" "0.65" "13.57" "2.97" ...
FALSE $ 2009 : chr [1:1036] "0.47" "0.55" "17.40" "3.51" ...
FALSE $ 2010 : chr [1:1036] "0.65" "0.56" "16.80" "3.77" ...
FALSE $ 2011 : chr [1:1036] "0.75" "0.56" "18.57" "4.15" ...
FALSE $ 2012 : chr [1:1036] "0.75" "0.49" "20.33" "4.61" ...
FALSE $ 2013 : chr [1:1036] "0.92" "0.56" "22.60" "5.69" ...
FALSE $ 2014 : chr [1:1036] "0.85" "0.62" "21.57" "5.61" ...
FALSE $ 2015 : chr [1:1036] "0.86" "0.63" "23.51" "5.06" ...
FALSE $ 2016 : chr [1:1036] "0.80" "0.62" "23.19" "5.03" ...
FALSE $ 2017 : chr [1:1036] "0.84" "0.70" "23.91" "4.14" ...
FALSE $ 2018 : chr [1:1036] "0.86781928" "0.70320991" "25.8825776" "4.191584" ...
FALSE $ 2019 : chr [1:1036] "0.89489653" "0.71658967" "27.0897153" "4.2916661" ...
FALSE - attr(*, "spec")=
FALSE .. cols(
FALSE .. Sector = col_character(),
FALSE .. country_name = col_character(),
FALSE .. `1970` = col_character(),
FALSE .. `1971` = col_character(),
FALSE .. `1972` = col_character(),
FALSE .. `1973` = col_character(),
FALSE .. `1974` = col_character(),
FALSE .. `1975` = col_character(),
FALSE .. `1976` = col_character(),
FALSE .. `1977` = col_character(),
FALSE .. `1978` = col_character(),
FALSE .. `1979` = col_character(),
FALSE .. `1980` = col_character(),
FALSE .. `1981` = col_character(),
FALSE .. `1982` = col_character(),
FALSE .. `1983` = col_character(),
FALSE .. `1984` = col_character(),
FALSE .. `1985` = col_character(),
FALSE .. `1986` = col_character(),
FALSE .. `1987` = col_character(),
FALSE .. `1988` = col_character(),
FALSE .. `1989` = col_character(),
FALSE .. `1990` = col_character(),
FALSE .. `1991` = col_character(),
FALSE .. `1992` = col_character(),
FALSE .. `1993` = col_character(),
FALSE .. `1994` = col_character(),
FALSE .. `1995` = col_character(),
FALSE .. `1996` = col_character(),
FALSE .. `1997` = col_character(),
FALSE .. `1998` = col_character(),
FALSE .. `1999` = col_character(),
FALSE .. `2000` = col_character(),
FALSE .. `2001` = col_character(),
FALSE .. `2002` = col_character(),
FALSE .. `2003` = col_character(),
FALSE .. `2004` = col_character(),
FALSE .. `2005` = col_character(),
FALSE .. `2006` = col_character(),
FALSE .. `2007` = col_character(),
FALSE .. `2008` = col_character(),
FALSE .. `2009` = col_character(),
FALSE .. `2010` = col_character(),
FALSE .. `2011` = col_character(),
FALSE .. `2012` = col_character(),
FALSE .. `2013` = col_character(),
FALSE .. `2014` = col_character(),
FALSE .. `2015` = col_character(),
FALSE .. `2016` = col_character(),
FALSE .. `2017` = col_character(),
FALSE .. `2018` = col_character(),
FALSE .. `2019` = col_character()
FALSE .. )
FALSE - attr(*, "problems")=<externalptr>
summary(co_data)
FALSE Sector country_name 1970 1971
FALSE Length:1036 Length:1036 Length:1036 Length:1036
FALSE Class :character Class :character Class :character Class :character
FALSE Mode :character Mode :character Mode :character Mode :character
FALSE 1972 1973 1974 1975
FALSE Length:1036 Length:1036 Length:1036 Length:1036
FALSE Class :character Class :character Class :character Class :character
FALSE Mode :character Mode :character Mode :character Mode :character
FALSE 1976 1977 1978 1979
FALSE Length:1036 Length:1036 Length:1036 Length:1036
FALSE Class :character Class :character Class :character Class :character
FALSE Mode :character Mode :character Mode :character Mode :character
FALSE 1980 1981 1982 1983
FALSE Length:1036 Length:1036 Length:1036 Length:1036
FALSE Class :character Class :character Class :character Class :character
FALSE Mode :character Mode :character Mode :character Mode :character
FALSE 1984 1985 1986 1987
FALSE Length:1036 Length:1036 Length:1036 Length:1036
FALSE Class :character Class :character Class :character Class :character
FALSE Mode :character Mode :character Mode :character Mode :character
FALSE 1988 1989 1990 1991
FALSE Length:1036 Length:1036 Length:1036 Length:1036
FALSE Class :character Class :character Class :character Class :character
FALSE Mode :character Mode :character Mode :character Mode :character
FALSE 1992 1993 1994 1995
FALSE Length:1036 Length:1036 Length:1036 Length:1036
FALSE Class :character Class :character Class :character Class :character
FALSE Mode :character Mode :character Mode :character Mode :character
FALSE 1996 1997 1998 1999
FALSE Length:1036 Length:1036 Length:1036 Length:1036
FALSE Class :character Class :character Class :character Class :character
FALSE Mode :character Mode :character Mode :character Mode :character
FALSE 2000 2001 2002 2003
FALSE Length:1036 Length:1036 Length:1036 Length:1036
FALSE Class :character Class :character Class :character Class :character
FALSE Mode :character Mode :character Mode :character Mode :character
FALSE 2004 2005 2006 2007
FALSE Length:1036 Length:1036 Length:1036 Length:1036
FALSE Class :character Class :character Class :character Class :character
FALSE Mode :character Mode :character Mode :character Mode :character
FALSE 2008 2009 2010 2011
FALSE Length:1036 Length:1036 Length:1036 Length:1036
FALSE Class :character Class :character Class :character Class :character
FALSE Mode :character Mode :character Mode :character Mode :character
FALSE 2012 2013 2014 2015
FALSE Length:1036 Length:1036 Length:1036 Length:1036
FALSE Class :character Class :character Class :character Class :character
FALSE Mode :character Mode :character Mode :character Mode :character
FALSE 2016 2017 2018 2019
FALSE Length:1036 Length:1036 Length:1036 Length:1036
FALSE Class :character Class :character Class :character Class :character
FALSE Mode :character Mode :character Mode :character Mode :character
str(temp)
FALSE spec_tbl_df [25,933 x 6] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
FALSE $ ID_coords: num [1:25933] 1 1 1 1 1 1 1 1 1 1 ...
FALSE $ lon : num [1:25933] -3.35 -3.35 -3.35 -3.35 -3.35 -3.35 -3.35 -3.35 -3.35 -3.35 ...
FALSE $ lat : num [1:25933] 40.5 40.5 40.5 40.5 40.5 ...
FALSE $ date : Date[1:25933], format: "1950-01-01" "1950-01-02" ...
FALSE $ Tmin : num [1:25933] 4.38 1.02 0.39 2.17 1.08 -0.88 0.11 2.78 4.66 3.56 ...
FALSE $ Tmax : num [1:25933] 9.67 10.59 11.38 14.73 13.11 ...
FALSE - attr(*, "spec")=
FALSE .. cols(
FALSE .. ID_coords = col_double(),
FALSE .. lon = col_double(),
FALSE .. lat = col_double(),
FALSE .. date = col_date(format = ""),
FALSE .. Tmin = col_double(),
FALSE .. Tmax = col_double()
FALSE .. )
FALSE - attr(*, "problems")=<externalptr>
summary(temp)
FALSE ID_coords lon lat date
FALSE Min. :1 Min. :-3.35 Min. :40.48 Min. :1950-01-01
FALSE 1st Qu.:1 1st Qu.:-3.35 1st Qu.:40.48 1st Qu.:1967-10-02
FALSE Median :1 Median :-3.35 Median :40.48 Median :1985-07-02
FALSE Mean :1 Mean :-3.35 Mean :40.48 Mean :1985-07-02
FALSE 3rd Qu.:1 3rd Qu.:-3.35 3rd Qu.:40.48 3rd Qu.:2003-04-02
FALSE Max. :1 Max. :-3.35 Max. :40.48 Max. :2020-12-31
FALSE Tmin Tmax
FALSE Min. :-11.520 Min. :-1.32
FALSE 1st Qu.: 3.180 1st Qu.:13.03
FALSE Median : 7.950 Median :19.40
FALSE Mean : 8.243 Mean :20.42
FALSE 3rd Qu.: 13.630 3rd Qu.:27.83
FALSE Max. : 24.240 Max. :41.41
También podemos realizar la exploración con View, esta
función está bien para ver los datos pero no nos muestra toda la
información.
View(co_data)
View(temp)
Podemos ver únicamente una muestra de los datos, para ello podemos
usar head, donde nos permite ver los primeros diez datos de
los dataframes.
head(co_data)
head(temp)
Finalmente también podemos utilizar glimpse, esta
función hace lo mismo que str pero de forma más
ordenada.
glimpse(co_data)
FALSE Rows: 1,036
FALSE Columns: 52
FALSE $ Sector <chr> "Buildings", "Buildings", "Buildings", "Buildings", "Buil~
FALSE $ country_name <chr> "Afghanistan", "Albania", "Algeria", "Angola", "Anguilla"~
FALSE $ `1970` <chr> "0.58", "0.99", "1.81", "0.12", "0.00", "0.06", "13.19", ~
FALSE $ `1971` <chr> "0.58", "0.99", "1.81", "0.12", "0.00", "0.06", "13.19", ~
FALSE $ `1972` <chr> "0.46", "1.10", "2.11", "0.14", "0.00", "0.08", "12.53", ~
FALSE $ `1973` <chr> "0.57", "1.30", "2.51", "0.14", "0.00", "0.08", "15.03", ~
FALSE $ `1974` <chr> "0.77", "1.41", "2.68", "0.13", "0.00", "0.06", "15.48", ~
FALSE $ `1975` <chr> "0.59", "1.75", "2.97", "0.12", "0.00", "0.08", "16.22", ~
FALSE $ `1976` <chr> "0.48", "1.91", "3.79", "0.09", "0.00", "0.06", "17.57", ~
FALSE $ `1977` <chr> "0.43", "2.02", "3.80", "0.10", "0.00", "0.07", "18.60", ~
FALSE $ `1978` <chr> "0.41", "2.21", "4.46", "0.33", "0.00", "0.06", "18.27", ~
FALSE $ `1979` <chr> "0.48", "2.69", "5.16", "0.56", "0.00", "0.06", "18.80", ~
FALSE $ `1980` <chr> "0.45", "1.73", "5.37", "0.70", "0.00", "0.06", "18.40", ~
FALSE $ `1981` <chr> "0.52", "1.81", "5.84", "0.66", "0.00", "0.06", "19.40", ~
FALSE $ `1982` <chr> "0.60", "1.90", "6.24", "0.38", "0.00", "0.07", "18.64", ~
FALSE $ `1983` <chr> "0.94", "2.01", "7.04", "0.50", "0.00", "0.04", "20.14", ~
FALSE $ `1984` <chr> "0.99", "2.06", "7.76", "0.55", "0.00", "0.06", "20.54", ~
FALSE $ `1985` <chr> "1.28", "2.09", "4.87", "0.60", "0.00", "0.06", "20.83", ~
FALSE $ `1986` <chr> "1.20", "2.20", "5.60", "0.62", "0.00", "0.07", "20.21", ~
FALSE $ `1987` <chr> "0.79", "2.20", "6.01", "0.63", "0.00", "0.08", "21.72", ~
FALSE $ `1988` <chr> "0.85", "2.33", "6.03", "0.75", "0.00", "0.08", "22.63", ~
FALSE $ `1989` <chr> "0.98", "1.53", "6.76", "0.73", "0.00", "0.09", "21.19", ~
FALSE $ `1990` <chr> "1.04", "2.09", "6.59", "0.66", "0.00", "0.09", "22.01", ~
FALSE $ `1991` <chr> "0.99", "1.32", "7.54", "0.69", "0.00", "0.09", "22.12", ~
FALSE $ `1992` <chr> "0.69", "0.57", "7.78", "0.62", "0.00", "0.08", "22.23", ~
FALSE $ `1993` <chr> "0.60", "0.39", "8.23", "0.51", "0.00", "0.07", "22.98", ~
FALSE $ `1994` <chr> "0.63", "0.33", "8.17", "0.63", "0.00", "0.08", "24.08", ~
FALSE $ `1995` <chr> "0.36", "0.33", "8.09", "0.67", "0.00", "0.08", "24.72", ~
FALSE $ `1996` <chr> "0.33", "0.45", "8.31", "0.91", "0.00", "0.08", "25.29", ~
FALSE $ `1997` <chr> "0.36", "0.38", "7.98", "0.91", "0.00", "0.08", "24.76", ~
FALSE $ `1998` <chr> "0.29", "0.29", "8.63", "1.01", "0.00", "0.04", "24.79", ~
FALSE $ `1999` <chr> "0.29", "0.75", "9.09", "1.26", "0.00", "0.06", "26.32", ~
FALSE $ `2000` <chr> "0.21", "0.76", "9.33", "1.05", "0.00", "0.05", "27.00", ~
FALSE $ `2001` <chr> "0.12", "0.80", "9.53", "1.17", "0.00", "0.04", "25.70", ~
FALSE $ `2002` <chr> "0.05", "1.17", "9.89", "1.20", "0.00", "0.05", "24.73", ~
FALSE $ `2003` <chr> "0.03", "1.04", "10.68", "1.26", "0.00", "0.05", "26.97",~
FALSE $ `2004` <chr> "0.04", "0.88", "11.51", "1.30", "0.00", "0.04", "29.54",~
FALSE $ `2005` <chr> "0.08", "0.70", "12.50", "1.00", "0.00", "0.04", "31.25",~
FALSE $ `2006` <chr> "0.11", "0.93", "12.19", "1.96", "0.00", "0.04", "32.83",~
FALSE $ `2007` <chr> "0.16", "0.72", "13.60", "2.33", "0.00", "0.04", "33.16",~
FALSE $ `2008` <chr> "0.32", "0.65", "13.57", "2.97", "0.00", "0.03", "37.37",~
FALSE $ `2009` <chr> "0.47", "0.55", "17.40", "3.51", "0.00", "0.04", "36.48",~
FALSE $ `2010` <chr> "0.65", "0.56", "16.80", "3.77", "0.00", "0.05", "36.48",~
FALSE $ `2011` <chr> "0.75", "0.56", "18.57", "4.15", "0.00", "0.04", "33.71",~
FALSE $ `2012` <chr> "0.75", "0.49", "20.33", "4.61", "0.00", "0.06", "35.48",~
FALSE $ `2013` <chr> "0.92", "0.56", "22.60", "5.69", "0.00", "0.10", "37.59",~
FALSE $ `2014` <chr> "0.85", "0.62", "21.57", "5.61", "0.00", "0.07", "38.62",~
FALSE $ `2015` <chr> "0.86", "0.63", "23.51", "5.06", "0.00", "0.08", "39.36",~
FALSE $ `2016` <chr> "0.80", "0.62", "23.19", "5.03", "0.00", "0.08", "39.71",~
FALSE $ `2017` <chr> "0.84", "0.70", "23.91", "4.14", "0.00", "0.06", "38.31",~
FALSE $ `2018` <chr> "0.86781928", "0.70320991", "25.8825776", "4.191584", "1.~
FALSE $ `2019` <chr> "0.89489653", "0.71658967", "27.0897153", "4.2916661", "1~
glimpse(temp)
FALSE Rows: 25,933
FALSE Columns: 6
FALSE $ ID_coords <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ~
FALSE $ lon <dbl> -3.35, -3.35, -3.35, -3.35, -3.35, -3.35, -3.35, -3.35, -3.3~
FALSE $ lat <dbl> 40.48, 40.48, 40.48, 40.48, 40.48, 40.48, 40.48, 40.48, 40.4~
FALSE $ date <date> 1950-01-01, 1950-01-02, 1950-01-03, 1950-01-04, 1950-01-05,~
FALSE $ Tmin <dbl> 4.38, 1.02, 0.39, 2.17, 1.08, -0.88, 0.11, 2.78, 4.66, 3.56,~
FALSE $ Tmax <dbl> 9.67, 10.59, 11.38, 14.73, 13.11, 10.87, 8.28, 12.06, 9.99, ~
tibble es una reinterpretación moderna de lo que es un
dataframe, al igual que todas las funciones de tidyverse es
más exigente con el código que rbase. Otra diferencia
notable es que tibble presenta un formato mucho más
consistente que un dataframe de rbase.
Un dataframe se puede devolver en forma de un vector o de otro dataframe (lo cual hace que sea inconsistente). Mientras que un tibble siempre se devuelve en el código en forma de tibble.
Ejemplo:
Podemos guardar un columna de un dataframe en forma de un vector:
v1 <- co_data [,1]
class(v1)# vemos que es un vector
FALSE [1] "tbl_df" "tbl" "data.frame"
Posteriomente podemos pasar este vector a dataframe:
v1 <- as.dataframe (co_data [,1])
FALSE Error in as.dataframe(co_data[, 1]): could not find function "as.dataframe"
class(v1)# vemos que es un dataframe
FALSE [1] "tbl_df" "tbl" "data.frame"
Ejemplo de la creación de un tibble:
Para su creación usamos la función tibble:
t1 <- tibble (
x = 1,
y = 1
)
Cualquier dato tipo tidy debe cumplir:
Como podemos apreciar el formato tidy de los datos ayuda a simplificar y a ordenar nuestros datos de trabajo, es un paso esencial cuando se trabaja con grandes bases de datos. Este formato de los datos nos ayuda a trabajar de forma más eficiente, limpia y reproducible con nuestros datos.
Así el paquete tidyr de tidyverse compila
una serie de funciones que nos permiten organizar y limpiar nuestros
datos para que adquieran un formato tidy.
Para saberlo haremos una exploración de este datafram y usaremos la
función glimpse:
glimpse (co_data)
FALSE Rows: 1,036
FALSE Columns: 52
FALSE $ Sector <chr> "Buildings", "Buildings", "Buildings", "Buildings", "Buil~
FALSE $ country_name <chr> "Afghanistan", "Albania", "Algeria", "Angola", "Anguilla"~
FALSE $ `1970` <chr> "0.58", "0.99", "1.81", "0.12", "0.00", "0.06", "13.19", ~
FALSE $ `1971` <chr> "0.58", "0.99", "1.81", "0.12", "0.00", "0.06", "13.19", ~
FALSE $ `1972` <chr> "0.46", "1.10", "2.11", "0.14", "0.00", "0.08", "12.53", ~
FALSE $ `1973` <chr> "0.57", "1.30", "2.51", "0.14", "0.00", "0.08", "15.03", ~
FALSE $ `1974` <chr> "0.77", "1.41", "2.68", "0.13", "0.00", "0.06", "15.48", ~
FALSE $ `1975` <chr> "0.59", "1.75", "2.97", "0.12", "0.00", "0.08", "16.22", ~
FALSE $ `1976` <chr> "0.48", "1.91", "3.79", "0.09", "0.00", "0.06", "17.57", ~
FALSE $ `1977` <chr> "0.43", "2.02", "3.80", "0.10", "0.00", "0.07", "18.60", ~
FALSE $ `1978` <chr> "0.41", "2.21", "4.46", "0.33", "0.00", "0.06", "18.27", ~
FALSE $ `1979` <chr> "0.48", "2.69", "5.16", "0.56", "0.00", "0.06", "18.80", ~
FALSE $ `1980` <chr> "0.45", "1.73", "5.37", "0.70", "0.00", "0.06", "18.40", ~
FALSE $ `1981` <chr> "0.52", "1.81", "5.84", "0.66", "0.00", "0.06", "19.40", ~
FALSE $ `1982` <chr> "0.60", "1.90", "6.24", "0.38", "0.00", "0.07", "18.64", ~
FALSE $ `1983` <chr> "0.94", "2.01", "7.04", "0.50", "0.00", "0.04", "20.14", ~
FALSE $ `1984` <chr> "0.99", "2.06", "7.76", "0.55", "0.00", "0.06", "20.54", ~
FALSE $ `1985` <chr> "1.28", "2.09", "4.87", "0.60", "0.00", "0.06", "20.83", ~
FALSE $ `1986` <chr> "1.20", "2.20", "5.60", "0.62", "0.00", "0.07", "20.21", ~
FALSE $ `1987` <chr> "0.79", "2.20", "6.01", "0.63", "0.00", "0.08", "21.72", ~
FALSE $ `1988` <chr> "0.85", "2.33", "6.03", "0.75", "0.00", "0.08", "22.63", ~
FALSE $ `1989` <chr> "0.98", "1.53", "6.76", "0.73", "0.00", "0.09", "21.19", ~
FALSE $ `1990` <chr> "1.04", "2.09", "6.59", "0.66", "0.00", "0.09", "22.01", ~
FALSE $ `1991` <chr> "0.99", "1.32", "7.54", "0.69", "0.00", "0.09", "22.12", ~
FALSE $ `1992` <chr> "0.69", "0.57", "7.78", "0.62", "0.00", "0.08", "22.23", ~
FALSE $ `1993` <chr> "0.60", "0.39", "8.23", "0.51", "0.00", "0.07", "22.98", ~
FALSE $ `1994` <chr> "0.63", "0.33", "8.17", "0.63", "0.00", "0.08", "24.08", ~
FALSE $ `1995` <chr> "0.36", "0.33", "8.09", "0.67", "0.00", "0.08", "24.72", ~
FALSE $ `1996` <chr> "0.33", "0.45", "8.31", "0.91", "0.00", "0.08", "25.29", ~
FALSE $ `1997` <chr> "0.36", "0.38", "7.98", "0.91", "0.00", "0.08", "24.76", ~
FALSE $ `1998` <chr> "0.29", "0.29", "8.63", "1.01", "0.00", "0.04", "24.79", ~
FALSE $ `1999` <chr> "0.29", "0.75", "9.09", "1.26", "0.00", "0.06", "26.32", ~
FALSE $ `2000` <chr> "0.21", "0.76", "9.33", "1.05", "0.00", "0.05", "27.00", ~
FALSE $ `2001` <chr> "0.12", "0.80", "9.53", "1.17", "0.00", "0.04", "25.70", ~
FALSE $ `2002` <chr> "0.05", "1.17", "9.89", "1.20", "0.00", "0.05", "24.73", ~
FALSE $ `2003` <chr> "0.03", "1.04", "10.68", "1.26", "0.00", "0.05", "26.97",~
FALSE $ `2004` <chr> "0.04", "0.88", "11.51", "1.30", "0.00", "0.04", "29.54",~
FALSE $ `2005` <chr> "0.08", "0.70", "12.50", "1.00", "0.00", "0.04", "31.25",~
FALSE $ `2006` <chr> "0.11", "0.93", "12.19", "1.96", "0.00", "0.04", "32.83",~
FALSE $ `2007` <chr> "0.16", "0.72", "13.60", "2.33", "0.00", "0.04", "33.16",~
FALSE $ `2008` <chr> "0.32", "0.65", "13.57", "2.97", "0.00", "0.03", "37.37",~
FALSE $ `2009` <chr> "0.47", "0.55", "17.40", "3.51", "0.00", "0.04", "36.48",~
FALSE $ `2010` <chr> "0.65", "0.56", "16.80", "3.77", "0.00", "0.05", "36.48",~
FALSE $ `2011` <chr> "0.75", "0.56", "18.57", "4.15", "0.00", "0.04", "33.71",~
FALSE $ `2012` <chr> "0.75", "0.49", "20.33", "4.61", "0.00", "0.06", "35.48",~
FALSE $ `2013` <chr> "0.92", "0.56", "22.60", "5.69", "0.00", "0.10", "37.59",~
FALSE $ `2014` <chr> "0.85", "0.62", "21.57", "5.61", "0.00", "0.07", "38.62",~
FALSE $ `2015` <chr> "0.86", "0.63", "23.51", "5.06", "0.00", "0.08", "39.36",~
FALSE $ `2016` <chr> "0.80", "0.62", "23.19", "5.03", "0.00", "0.08", "39.71",~
FALSE $ `2017` <chr> "0.84", "0.70", "23.91", "4.14", "0.00", "0.06", "38.31",~
FALSE $ `2018` <chr> "0.86781928", "0.70320991", "25.8825776", "4.191584", "1.~
FALSE $ `2019` <chr> "0.89489653", "0.71658967", "27.0897153", "4.2916661", "1~
Como se puede apreciar, nuestro dataframe co_data no cumple las características para ser un dato tipo tidy, ya que en el encontramos variables innecesarias que se pueden simplificar, por ejemplo los datos de año esta dispuestos como una variable cada uno, cuando se podría generar una sola variable llamada año que recogiese todos los años muestreados y los relacionase con los valores de CO2.
El formato en el que se encuentra actualmente estos datos se conoce como un formato ancho, donde existen muchas variables. Por ello, para que sea un dato tidy debemos pasarlo a un formato largo, donde existen menos variables.
En el formato largo haremos que solo existan 3 variables: - una para los niveles de CO2 - otra para los años - una final para los países
Para conseguir pasar de un formato ancho a un formato largo debemos
utilizar la función pivot_longer ( dentro de
pivot existen principalmente dos funciones
pivot_longer que pasa a un formato largo y
pivot_wider que pasa a un formato ancho).
co_data2 <- co_data %>%
pivot_longer(
cols = "1970":"2019",# señalamos el rango de columnas que vamos a cambiar
names_to = "co_year", # a donde va a ir esas columnas (la nueva variable)
values_to = "co_value"# a donde van los valores de esas columnas de cada año (a donde van los datos de CO2 por año)
)
La pipa coge un resultado previo y lo pasa a la siguiente función
(concatena funciones). Ya existía en otros lenguajes de programación. En
R apareció de repente en 2014, debido a que su uso facilita la lectura y
escritura de código de forma considerable. Su shortcut es:
ctrl + shift + m
Mediante el uso de dplyr seguiremos trabajando los datos
a través de diferentes funciones.
filter permite seleccionar filas, mientras que
select permite seleccionar columnas.
Datos de CO2:
Una vez que hemos pasado los datos de CO2 a formato tidy
vamos a visualizarlos con glimpse
glimpse (co_data2)
FALSE Rows: 51,800
FALSE Columns: 4
FALSE $ Sector <chr> "Buildings", "Buildings", "Buildings", "Buildings", "Buil~
FALSE $ country_name <chr> "Afghanistan", "Afghanistan", "Afghanistan", "Afghanistan~
FALSE $ co_year <chr> "1970", "1971", "1972", "1973", "1974", "1975", "1976", "~
FALSE $ co_value <chr> "0.58", "0.58", "0.46", "0.57", "0.77", "0.59", "0.48", "~
Pero al observar los datos vmos que tenemos información de todos los
países, a nosotros solo nos interesa España para nuestro problema
ambiental, por lo que usaremos filter para seleccionar
aquellos datos que sean de España y lo guardaremos:
co_data_s <- co_data2 %>%
filter(country_name == "Spain and Andorra")
Datos de temperatura:
Ahora trabajaremos con los datos de temperatura, para ello primero
comprobamos la estructura de los datos con str:
str(temp)
FALSE spec_tbl_df [25,933 x 6] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
FALSE $ ID_coords: num [1:25933] 1 1 1 1 1 1 1 1 1 1 ...
FALSE $ lon : num [1:25933] -3.35 -3.35 -3.35 -3.35 -3.35 -3.35 -3.35 -3.35 -3.35 -3.35 ...
FALSE $ lat : num [1:25933] 40.5 40.5 40.5 40.5 40.5 ...
FALSE $ date : Date[1:25933], format: "1950-01-01" "1950-01-02" ...
FALSE $ Tmin : num [1:25933] 4.38 1.02 0.39 2.17 1.08 -0.88 0.11 2.78 4.66 3.56 ...
FALSE $ Tmax : num [1:25933] 9.67 10.59 11.38 14.73 13.11 ...
FALSE - attr(*, "spec")=
FALSE .. cols(
FALSE .. ID_coords = col_double(),
FALSE .. lon = col_double(),
FALSE .. lat = col_double(),
FALSE .. date = col_date(format = ""),
FALSE .. Tmin = col_double(),
FALSE .. Tmax = col_double()
FALSE .. )
FALSE - attr(*, "problems")=<externalptr>
Puede que lo de temperatura no este en formato tidy, pero lo dejamos
así porque vamos a usar la temperatura media. La columna de id no es
necesaria porque todos los datos son de Alcalá de Henares, por lo que
vamos a eliminarla. Para quitar columnas en tidyverse no se borran
columnas, sino que se seleccionan las columnas que quieres utilizando la
función select.
temp_sel <- temp %>%
dplyr::select(!ID_coords) # podríamos hacerlo con - pero lo correcto es !, estamos seleccionando
# todas menos la columna del id
Como hemos mencionado anteriormente lo que queremos es utilizar es la
temperatura media de Alcalá de Henares, para ello vamos a generar una
nueva variable en la que se refleje la temperatura media, que se
calculará como la suma de las temperaturas máximas y mínimas entre 2.
Además tengo otro inconveniente con respecto a la temperatura y es que
en el apartado de fecha me aparecen los días, meses y años, pero solo
nos interesan los años, ya que agruparemos la temperatura en función de
estos. Para realizar todos estos cambios usaremos la función
mutate:
temp_f <- temp_sel %>%
mutate(
Tmean = (Tmax+Tmin)/2,
date = as.Date(date),
month = format(date, format = "%m"),
year = format(date, format = "%Y")
)
En la primera parte del código estamos definiendo la nueva variable
de temperatura media (Tmean) para ello, primero ponemos el
nombre de la nueva variable y luego que datos o valores contiene, en
este caso definimos que queremos que se calcule apartir de la media
entre la temperatura máxima y mínima. En cuanto a la fecha le indica que
nos extraiga los meses y días con “%m” y
“%Y”, redefiniendo la variable en el proceso.
Con la función mutate podemos generar nuevas variables
desde 0, indicando todos los valores de esa nueva variable.
A pesar de todo el trabajo que llevamos hasta ahora todavía no hemos
terminado de preparar los datos de temperatura ya que necesitamos que
los datos de temperatura media este organizados por año, pues para un
mismo año tenemos diferentes valores de temperatura media. Para
conseguir esto utilizaremos las funciones group_by y
summarise.
En primer lugar agruparemos los valores de temperatura media por año
utilizando la función group_by. Pero tras esta operación
sequiré teniendo varios datos de temperatura media por año, por ello lo
que haremos será resumir estos datos haciendo la media de las
temperaturas medias para cada año, esto lo conseguiremos utilizando la
función summarise. Así aplicaremos el siguiente código:
temp_mean <- temp_f %>%
group_by(year) %>%
summarise(
Tmean.year = mean(Tmean)
)
Como para nuestro problema ambiental queremos tener los datos de
CO2 y los de temperatura en un mismo tibble utilizaremos la
función join que me permite unir las columnas varios
dataframes o varios tibbles en uno solo por diversos métodos, donde se
selecciona la variable común por la que se quieren unir. Existen
principalmente cuatro tipos de join:
full_join: consiste en unir todas las columnas de los
dataframes o tibbles en uno sololeft_join: toma todas las columnas del primer dataframe
o tibble y las unirá solo con las columnas que tengan filas coincidentes
del segundo dataframe o tibbleright_join: toma todas las columnas del segundo
dataframe o tibble y las unirá solo con las columnas del primer
dataframe o tibble que tengan filas que coincidan en ambosinner_join: que solo unirá las columnas de los dos
dataframes o tibbles que tengan filas coincidentes.Estos concepto se entienden mejor con la siguiente imagen:
Utilizaremos un full_join para unir los datos de
CO2 y de temperatura por el año:
co_temp <- full_join(
temp_mean,
co_data_s,
by = c("year" = "co_year")
)
En este código hemos dicho que la columna “year” de temperatura es
igual que la columna ” co_year” de los datos de CO2, y hemos
unido las dos bases por medio de esta columna. Ahora que se han unido
nos queda organizar un poco la información, si nos fijamos en nuestro
nuevo tibble co_temp veremos que existen varios valores de
temperatura repetidos por sectores donde se ha medido el nivel de
CO2. Lo que sucede es que la temperatura anual media en
Alcalá de Henares es igual para cualquiera de los sectores pero no lo
son los niveles de CO2 emitidos, por lo que para los datos de
CO2debemos realizar la suma de los niveles de dióxido de
carbono por sector,por ello usaremos la función summarise.
Mientras que en el caso de la temperatura debemos eliminar los valores
repetidos, por ello nos quedaremos con los primeros valores de
temperatura que aparecen por año utilizando la función
first. Estas funciones las aplicaremos de forma simultánea,
pero hay un inconveniente y es que no se puede realizar la suma de los
niveles de CO2 por sector tal cual debido a que esta variable
está definida como un factor, por ello, antes de nada utilizaremos
mutate para transformarla en numérica.
co_temp_all <- co_temp %>%
mutate( co_value = as.numeric(co_value),
year = as.numeric(year) ) %>% # empleamos mutate pasando co_value year a una variable numérica
group_by(year) %>%
summarise(co_all =sum(co_value), Tmean.year= first(Tmean.year) )# realizamos la suma de los niveles de CO2 y tomamos los primeros valores de temperatura por año
Ahora que ya hemos terminado de organizar y depurar la información
solo nos queda visualizar los resultados, aquí es donde entra el paquete
ggplot, que permite producir diferentes tipos de gráficos
de forma relativamente sencilla. Debido a que este paquete es anterior
al resto de paquetes de tidyverse no funciona con la pipa (
%>% ), sino que emplea el símbolo “+”.
Más adelante, en el apartado de visualización de datos detallaremos
más a fondo el funcionamiento y sintaxis de ggplot, por lo
que en este apartado solo veremos unas nociones básicas de su
funcionamiento.
Haremos una nube de puntos sobre los datos de la temperatura media anual.
Para ello, primero llamamos a ggplot, definimos la base de datos que vamos a usar y definimos cuales son la variable x e y (aes hace referencia a aesthetics y sirve para indicar dentro de…), luego indicamos que tipo de representación queremos realizar.
ggplot(co_temp, aes(x = year, y = Tmean.year))+
geom_point()
FALSE Error : The fig.showtext code chunk option must be TRUE
Al observar la nube de puntos generada vemos que algunos puntos (que
son las observaciones) se solapan, esto se debe a que estamos utilizando
la base de datos antigua donde hay datos de temperatura repetidos por
año, simplemente debemos usar la base de datos más reciente donde
habíamos realizado un summarise.
ggplot(co_temp_all, aes(x = year, y = Tmean.year)) +
geom_point()
FALSE Error : The fig.showtext code chunk option must be TRUE
Este paquete de tidyverse contiene funciones que
facilitan el trabajo con string.
Los string son vectores compuestos por palabras. Este tipo de vectores se emplean en e minado de texto, donde extraemos datos de forma automatizada de documentos.
Ejemplo:
co_temp_s <- co_temp %>%
mutate( other = str_detect(Sector, "Other") )
# Aquí hemos utilizado una función del paquete `stringr` para que genere una nueva variable llamada `other` donde se determina si pertenecen a datos de un sector que lleve la palabra "other" (TRUE) o no (FALSE).
Este paquete compila una serie de funciones que facilita el trabajo
con factores. Todas las funciones de este paquete empiezan por la
partícula “fct”. Existen funciones como relevel que
reordena los vectores según un orden definido.
Ejemplo:
co_temp_fs <- co_temp %>%
mutate(
Sector = fct_relevel(Sector, "Other industrial combustion", after = Inf),
Sector = fct_relevel(Sector, "Other sectors", after = Inf)
)
# Aquí hemos utilizado la función fct_relevel para reorganizar los datos de forma que aquellas filas donde el sector sea "Other industrial combustion" y donde el sector sea "Other sectors" salgan como último y penúltimo respectivamente por año.
Con las funciones del paquete de purrr puedo conseguir
crear funciones en bucle y de forma automatizada, por ejemplo podemos
aplicar funciones de purrr, para que apliquen un
determinado tema a las figuras y gráficos de ggplot y hacer
que se ejecute en bucle sobre los elementos de una lista. Con respecto a
la sintaxis, la mayoría de funciones de purrr suelen
contener la partícula “map”
Ejemplo:
En rbase podríamos generar la siguiente función:
select_julen <- function (df, x) # aquí df y x son argumentos
{df[,x]}
Con purrr podríamos generar la misma función y aplicarla en bucle.
En este apartado nos centraremos en la generación de diferentes tipos
de gráficos con ggplot
Los gráficos pueden ser:
Histogramas: permite visualizar los datos, nos puede indicar la distribución de los datos, el eje de la Y es count (cuenta/ cantidad). X es una variable continua.
Barplots (gráfico de barras): aquí la variable X puede ser discreta y la variable Y no es un count
Scatterplots (nubes de puntos): la línea de tendencia se conoce como smooth
Boxplot (caja de bigotes): es un gráfico de dispersión y nos permite de saber como de alejados están los datos, la linea del medio es la mediana
Para trabajar con ggplot, además de necesitar el paquete
de tidyverse, utilizaremos otros paquetes que nos
permitirán personalizar los gráficos. Por ello, cargamos las siguientes
librerías:
library(tidyverse)
library(lubridate)
FALSE
FALSE Attaching package: 'lubridate'
FALSE The following objects are masked from 'package:raster':
FALSE
FALSE intersect, union
FALSE The following objects are masked from 'package:base':
FALSE
FALSE date, intersect, setdiff, union
library(ggthemes)
library(wesanderson)
También vamos a cargar los datos con los que vamos a trabajar, en estos datos se recoge información sobre los seismos y niveles de SO2 por región sobre la erupción de la Palma que ha sucedido este mismo año, en el primer dataframe. En el segundo dataframe se recoge información más detallada sobre los seísmos (como la profundidad o magnitud de estos), además de otra información como la temperatura.
count_cumbre_vieja <- read_csv("cumbre_vieja_visualdata-main/count_cumbre_vieja.csv")
FALSE Rows: 117 Columns: 4
FALSE -- Column specification --------------------------------------------------------
FALSE Delimiter: ","
FALSE chr (1): Region
FALSE dbl (2): number, so2
FALSE date (1): date
FALSE
FALSE i Use `spec()` to retrieve the full column specification for this data.
FALSE i Specify the column types or set `show_col_types = FALSE` to quiet this message.
data_cumbre_vieja <- read_csv("cumbre_vieja_visualdata-main/data_cumbre_vieja.csv")
FALSE Rows: 332 Columns: 19
FALSE -- Column specification --------------------------------------------------------
FALSE Delimiter: ","
FALSE chr (2): Max. int, Region
FALSE dbl (16): Latitude, Longitude, Depth, Magnitude, day, pm1, pm10, pm25, temp...
FALSE date (1): date
FALSE
FALSE i Use `spec()` to retrieve the full column specification for this data.
FALSE i Specify the column types or set `show_col_types = FALSE` to quiet this message.
De momento trabajaremos con el primer dataframe,
count_cumbre_vieja.
Antes de comenzar a visualizar los datos en forma de gráficos debemos
observar el dataframe, para ello podemos utilizar por ejemplo, la
función View:
View(count_cumbre_vieja)
Vemos que tenemos cuatro variables:
Fecha en la que se produjeron los seísmos
La región de la Palma donde se registraron
El número de terremotos
Los niveles de SO2
Con respecto al dataframe de count_cumbre_vieja podemos
plantearnos ver las siguientes relaciones entre las variables, entre
otras:
Número de terremotos ~ Niveles de SO2
Número de terremotos ~ Región
Número de terremotos ~ Fecha
Niveles de SO2 ~Fecha
ggplot tiene 4 elementos principales:
La función de ggplot
Los datos a utilizar
Las variables definidas, donde empleamos
aes
El tipo de gráfico que queremos realizar y que sique la forma
geom_tipo
Un esquema general de la estructura de un gráfico ggplot
sería el siguiente:
ggplot(datos, aes(var_x, var_y)+
geom_tipodegrafico (loquequeremos,# donde his_hitograma,point_nube de puntos
alpha= gradodetransparencia,
size= tamañodelpunto,
color= color,
fill= fondo))
FALSE Error in geom_tipodegrafico(loquequeremos, alpha = gradodetransparencia, : could not find function "geom_tipodegrafico"
Donde geom_smooth es la línea de tendencia de una nube
de puntos y puede seguir diferentes modelos que detallaremos más
adelante
terremoto <- ggplot(data= count_cumbre_vieja,
aes(x=date, y= number))+
geom_point(color= "indianred",
size= 5,
alpha= 0.5)+
geom_smooth(color= "skyblue",
fill= "steelblue",
method= "lm")+
labs(x= "fecha",
y= "Número de terremotos",
title= "Erupción la Palma",
subtitle = "2021")+
theme_classic()
terremoto
FALSE Error : The fig.showtext code chunk option must be TRUE
FALSE `geom_smooth()` using formula 'y ~ x'
Donde:
method: permite definir el tipo de método por el que
se obtiene la línea de tendencia el tipo de método se ponemos entre
comillas. El método a usar depende de lo que queremos, aquí es mejor
utilizar el método default (que es el método “loess”), pero por probar
utilizamos “lm”, es decir, linear model.
labs: indica las etiquetas, puede ser títulos y
subtítulos o nombres de los ejes, se debe poner entre comillas ya que
sino R lo considera un objeto.
theme: permite definir el aspecto del gráfico, lo
mejor es dejarlo para el final.
Probamos ahora con el método “loess”
ggplot(data= count_cumbre_vieja,
aes(x=date, y= number))+
geom_line(linetype= "dashed",
color= "steelblue")+
geom_point(color= "skyblue",
size= 5,
alpha= 0.5)+
labs(x= "fecha",
y= "Número de terremotos",
title= "Erupción la Palma",
subtitle = "2021")+
theme_classic()
FALSE Error : The fig.showtext code chunk option must be TRUE
Como vemos, para este caso es mejor usar el método “loess” ya que nos
permite ver la gran variación del número de terremotos por fecha,
mientras que el método “lm” no nos aporta nada de información. También
existe un method que es el modelo aditivo (“gam”).
Como podemos apreciar en ggplot se pueden agregar
figuras sobre figuras al hacer varios geom consecutivos,
esto facilita mucho la generación de gráficos y simplifica el
código.
Podemos incluso guardar un gráfico como un objeto y posteriomente añadirle más elementos, por ejemplo:
terremoto2 <- terremoto +
geom_line(linetype= "dashed",
color= "darkblue")
terremoto2
FALSE Error : The fig.showtext code chunk option must be TRUE
FALSE `geom_smooth()` using formula 'y ~ x'
Dentro de un mismo gráfico podemos incluir información de una tercera variable, en nuestro caso donde vemos la relación entre el número de seísmos y la fecha, podemos realizar una diferenciación por regiones de estos datos.
Para conseguir esta diferenciación hay dos estrategias:
Generar una diferenciación por color, donde se genere un código de color que nos permita diferenciar los datos por regiones ( es decir, darle un color distinto a cada región).
Separar los datos en diferentes gráficos (donde existirá un gráfico para cada región).
Diferenciación por color
Para ello basta con indicar en geom_point que queremos
colorear por región:
terre_region <- ggplot(data= count_cumbre_vieja,
aes(x=date, y= number))+
geom_point(aes(color= Region),
size= 2,
alpha= 0.5)+
labs(x= "fecha",
y= "Número de terremotos",
title= "Erupción la Palma",
subtitle = "2021")+
theme_classic()
terre_region
FALSE Error : The fig.showtext code chunk option must be TRUE
Podemos también generar la líneas de tendencia por regiones y personalizar más el gráfico.
terre_region2 <- ggplot(data= count_cumbre_vieja,
aes(x=date, y= number))+
geom_point(aes(color= Region),
size= 2,
alpha= 0.5)+
geom_smooth(aes(color= Region,
fill= Region)
)+
labs(x= "fecha", y= "Número de terremotos",
title= "Erupción la Palma", subtitle = "2021")+
theme_classic()
terre_region2
FALSE Error : The fig.showtext code chunk option must be TRUE
FALSE `geom_smooth()` using method = 'loess' and formula 'y ~ x'
Si nos fijamos en este segundo gráfico vemos que nos faltan las
líneas de tendencia de dos regiones, esto se debe a que solo hay una
observación para esas regiones y con un punto no se puede generar una
línea. Si nos damos cuenta podemos observar que el color usado en el
fill no coincide con el de las líneas de tendencia, esto se
debe a que la paleta de colores que usa ggplot usa los
colores en orden, y al no poder representar dos regiones los colores de
esas regiones se usan en las demás.
El color se puede definir manualmente para evitar estos pequeños errores.
En este caso al solo tener dos regiones con línea de tendencia lo mejor es separar los datos en varias gráficas independientes.
¿Por qué usar color o fill?
: color se utiliza para colorear contornos, líneas
y puntos (elementos de una dimensión), mientras que fill se
emplea para colorear áreas.
Generación de diferentes gráficos por regiones
Para ello usamos la función facet_wrap:
terre_region3 <- terre_region2 +
facet_wrap(.~Region)
terre_region3
FALSE Error : The fig.showtext code chunk option must be TRUE
FALSE `geom_smooth()` using method = 'loess' and formula 'y ~ x'
Aquí no hay que poner aes, ya que aes se
pone con los geom. Podemos poner el área de tendencia de un
color solo o en gris (en gris es por defecto y para ello bastaría con
quitar el fill).
Como consejo para cualquier estudio, cuando hagamos un scatterplot lo mejor es utilizar un linear model (“lm”) al principio, para ver si se ajusta a un modelo lineal, si vemos que el ajuste no es bueno podemos probar con otros métodos.
terre_so2 <- ggplot(data= count_cumbre_vieja,
aes(x=number,
y= so2))+
geom_point(color= "coral1",
size= 2,
alpha= 0.5)+
geom_smooth(method="lm")+
theme_classic()
terre_so2
FALSE Error : The fig.showtext code chunk option must be TRUE
FALSE `geom_smooth()` using formula 'y ~ x'
Podemos apreciar que no se ajusta bien a un modelo lineal.
Ahora comenzamos a trabajar con el segundo dataframe y vamos a ver la relación entre la fecha y la magnitud de los terremotos.
ggplot(data=data_cumbre_vieja,
aes(x= date,
y= Magnitude))+
geom_point(aes(size= Magnitude),
alpha= 0.25)+
geom_smooth()
FALSE Error : The fig.showtext code chunk option must be TRUE
FALSE `geom_smooth()` using method = 'loess' and formula 'y ~ x'
Aquí hemos representamos la relación entre la fecha de los terremotos y la magnitud de estos, hemos definido que le tamaño de los puntos varíe en función de la magnitud de los terremotos para que la visualización resulte más sencilla. Aunque esta diferenciación sería más correcta hacerla si la magnitud no estuviese ya representada en el gráfico, porque da información redundante.
Podemos realizar la diferenciación del tamaño de los puntos en función de la profundidad de los seísmos, donde a menor profundidad más grandes srán los puntos, debido a que al ser más superficiales se sienten más fácilmente por la población. A este respecto nos surge un inconveniente, y es que R por si solo hará más grande los puntos con mayor valor de profundidad, para cambiar esto basta con invertir el valor de la profundidad en el código al poner un “-” delante. El cambiar el tamaño para facilitar la visualización es mejor utilizarlo con variables continuas, con variables categóricas seria mejor realizar una diferenciación con colores o facets.
mag_pro <- ggplot(data=data_cumbre_vieja,
aes(x= date,
y= Magnitude))+
geom_point(aes(size= -Depth, color= -Depth),
alpha= 0.25)+
geom_smooth()+
scale_color_gradientn(colors = rev(wes_palette("Zissou1",)))+
theme_classic()
mag_pro
FALSE Error : The fig.showtext code chunk option must be TRUE
FALSE `geom_smooth()` using method = 'loess' and formula 'y ~ x'
Hemos invertido la escala de colores para que vaya acorde con la profundidad y que refleje la intensidad con la que sentiríamos los seísmos
Los boxplots se componen de una sola variable y pueden representarse varios en base a otra variable categórica, nos permiten ver la dispersión de los datos.
Por defecto los boxplots se orientan según el eje y, hemos realizado un bosxplot sobre la magnitud de los terremotos.
ggplot(data=data_cumbre_vieja,
aes(y= Magnitude))+
geom_boxplot()
FALSE Error : The fig.showtext code chunk option must be TRUE
Podemos ver que sucede si realizamos una diferenciación por regiones:
ggplot(data=data_cumbre_vieja,
aes(y= Magnitude, x= Region))+
geom_boxplot(color= "black",
aes(fill= Region))+
theme_light()+
theme(legend.position= "none")
FALSE Error : The fig.showtext code chunk option must be TRUE
Hemos quitado la leyenda porque los nombres de las regiones ya aparecen. La región de Tazacorte se representa con una única línea debido a que solo tiene una observación. Las personalizaciones del tema (como la posición de la leyenda, por ejemplo) van lo último porque sino se solapan con el tema y da fallos, por ejemplo si lo de la leyenda no fuese lo último, me aparecería porque forma parte del tema que hemos usado.
Vamos a relacionar por medio de un barplot el número de terremotos
con la región. Si hacemos el barplot tal cual nos dará un error,
diciéndonos que solo podemos utilizar una variable, para solucionar este
fallo basta con usar el parche stat= "identity". Para
diferenciar las regiones colorearemos de forma diferencial el barplot
según la región (usamos la función fill porque estamos
coloreando un área).
ggplot(data= count_cumbre_vieja,
aes(x= Region,
y= number))+
geom_bar(stat = "identity",
aes(fill= Region))
FALSE Error : The fig.showtext code chunk option must be TRUE
Para que fuese estadísticamente correcto habría que poner barras de error en el gráfico.
Un histograma nos indica la frecuencia con la que se repite un dato y además, nos permite ver la distribución de datos.
Vamos a realizar un histograma sobre la magnitud de los terremotos.
his_1 <- ggplot(data= data_cumbre_vieja,
aes(x = Magnitude))+
geom_histogram(fill = "forestgreen",
bins = 200,
binwidth = 0.1)+
theme_clean()+
labs(y = "Frecuencia",
x = "Magnitud",
title = "Histograma 1")
his_1
FALSE Error : The fig.showtext code chunk option must be TRUE
Donde bins es el numero de barras del gráfico y
binwidth permite ajustar el grosor de las barras.
Por último podemos realizar diagramas de densidad para ver también la distribución de los datos, vamos a realizar un diagrama de densidad con la magnitud.
den_1 <- ggplot(data= data_cumbre_vieja,
aes(x = Magnitude))+
geom_density(fill = "#E88873",
color = "#E05C3E",
alpha = 0.5)+
theme_clean()
den_1
FALSE Error : The fig.showtext code chunk option must be TRUE
A lo largo de este bloque trabajaremos en la creación de mapas y en el uso de R como GIS
Los sistemas GIS o SIG son sistemas de información geográfica, es decir, son programas informáticos que nos permiten trabajar con datos geográficos y tienen muchísimas utilidades en una gran variedad de campos.
Estos integran información digital la analizan y la representan. Los sistemas GIS funcionan por capas, suelen ser mapas o atributos mapeables, hay distintos tipos de capas como poligonales, lineales, de puntos, etc. Todas las capas deben ser del mismo tipo.
En estos sistemas podemos distinguir entre dos tipos principales de datos:
Datos en formato raster (fotografía)
Datos en formato vectorial(esta información está codificado de diferente forma)
¿Cuál es mejor, raster o vectorial?
Al trabajar con raster vamos a tener problemas en función de la resolución de la imagen por lo que los datos de tipo vectorial son más fieles a la realidad. Por lo tanto, a este respecto es mejor utilizar datos de tipo vectorial, pero hay ocasiones donde nos es indiferente cuál usar.
Tipos de archivos que usan los datos vectoriales
El tipo de archivo que más se usan en capas vectoriales son los archivos shapefile (shp), estos se componen de cinco archivos:
Tabla df: se trata de una tabla asociada a los atributos que quiero representar con la capa vectorial
prj: la proyección geográfica
shp: listas anidadas
xml: metadatos
shx: escala rotación
Tipos de archivos que usan los datos raster
Como hemos mencionado anteriormente los archivos tipo raster son imágenes y en consecuencia trabajamos con archivos de extensiones tiff, jpeg, etc. Hay otros tipos de archivos raster que se denominan net cdf, y se emplean para datos climáticos.
Existen diferentes tipos de programas que funcionan como GIS, tenemos por ejemplo, QGIS, ArcGIS o esri.
Proyecciones y sistemas de coordenadas
Todos estos programas se basan en sistemas de coordenadas y proyecciones geográficas.
Una proyección geográfica consiste en transferir la esfera de la tierra a un plano. Hay diferentes tipos de proyecciones geográficas:
Cilíndrica, que es la proyección más habitual
Accital, que va desde los polos polos
Cónica, esta es útil cuando trabajamos a nivel local.
Con respecto a los sistemas de coordenadas geográficas, estos se componen de latitud (norte-sur) y longitud (este-oeste), y todos estos van de - 180º a +180º. Existen muchos sistemas diferentes, uno de los más usados es el sistema UTM. En el sistema UTM se divide la superficie terrestre en cuadrículas de un determinado tamaño que siempre son iguales, se utiliza este sistema cuando área tiene importancia.
En este apartado veremos un ejemplo de como podemos utilizar R como GIS.
En primer lugar borramos el ambiente de trabajo:
rm(list=ls())
Definimos el directorio de trabajo:
setwd("C:/Users/tsuba/OneDrive/Escritorio/MANUAL")
Y a continuación cargamos las librerías que vamos a utilizar:
library(raster)
library(maptools)
FALSE Checking rgeos availability: TRUE
FALSE Please note that 'maptools' will be retired by the end of 2023,
FALSE plan transition at your earliest convenience;
FALSE some functionality will be moved to 'sp'.
library(sp)
library(sf)
FALSE Linking to GEOS 3.9.1, GDAL 3.2.1, PROJ 7.2.1; sf_use_s2() is TRUE
library(rgdal)
FALSE Please note that rgdal will be retired by the end of 2023,
FALSE plan transition to sf/stars/terra functions using GDAL and PROJ
FALSE at your earliest convenience.
FALSE
FALSE rgdal: version: 1.5-29, (SVN revision 1165M)
FALSE Geospatial Data Abstraction Library extensions to R successfully loaded
FALSE Loaded GDAL runtime: GDAL 3.2.1, released 2020/12/29
FALSE Path to GDAL shared files: C:/Users/tsuba/OneDrive/Documentos/R/win-library/4.1/rgdal/gdal
FALSE GDAL binary built with GEOS: TRUE
FALSE Loaded PROJ runtime: Rel. 7.2.1, January 1st, 2021, [PJ_VERSION: 721]
FALSE Path to PROJ shared files: C:/Users/tsuba/OneDrive/Documentos/R/win-library/4.1/rgdal/proj
FALSE PROJ CDN enabled: FALSE
FALSE Linking to sp version:1.4-6
FALSE To mute warnings of possible GDAL/OSR exportToProj4() degradation,
FALSE use options("rgdal_show_exportToProj4_warnings"="none") before loading sp or rgdal.
FALSE Overwritten PROJ_LIB was C:/Users/tsuba/OneDrive/Documentos/R/win-library/4.1/rgdal/proj
library(dismo)
library(spam)
FALSE Spam version 2.8-0 (2022-01-05) is loaded.
FALSE Type 'help( Spam)' or 'demo( spam)' for a short introduction
FALSE and overview of this package.
FALSE Help for individual functions is also obtained by adding the
FALSE suffix '.spam' to the function name, e.g. 'help( chol.spam)'.
FALSE
FALSE Attaching package: 'spam'
FALSE The following objects are masked from 'package:base':
FALSE
FALSE backsolve, forwardsolve
library(rworldmap)
FALSE ### Welcome to rworldmap ###
FALSE For a short introduction type : vignette('rworldmap')
library(rworldxtra)
library(jsonlite)
FALSE
FALSE Attaching package: 'jsonlite'
FALSE The following object is masked from 'package:purrr':
FALSE
FALSE flatten
library(rgeos)
FALSE rgeos version: 0.5-9, (SVN revision 684)
FALSE GEOS runtime version: 3.9.1-CAPI-1.14.2
FALSE Please note that rgeos will be retired by the end of 2023,
FALSE plan transition to sf functions using GEOS at your earliest convenience.
FALSE GEOS using OverlayNG
FALSE Linking to sp version: 1.4-6
FALSE Polygon checking: TRUE
library(mapSpain)
library(ggmap)
FALSE Google's Terms of Service: https://cloud.google.com/maps-platform/terms/.
FALSE Please cite ggmap if you use it! See citation("ggmap") for details.
FALSE
FALSE Attaching package: 'ggmap'
FALSE The following object is masked from 'package:dismo':
FALSE
FALSE geocode
library(ggplot2)
library(maps)
FALSE
FALSE Attaching package: 'maps'
FALSE The following object is masked from 'package:viridis':
FALSE
FALSE unemp
FALSE The following object is masked from 'package:purrr':
FALSE
FALSE map
library(mapdata)
library(marmap)
FALSE Registered S3 methods overwritten by 'adehabitatMA':
FALSE method from
FALSE print.SpatialPixelsDataFrame sp
FALSE print.SpatialPixels sp
FALSE
FALSE Attaching package: 'marmap'
FALSE The following object is masked from 'package:raster':
FALSE
FALSE as.raster
FALSE The following object is masked from 'package:grDevices':
FALSE
FALSE as.raster
library(mapproj)
library(slippymath)
library(ggspatial)
Utilizando el paquete mapSpain vamos a descargarnos
datos geográficos del mundo en alta resolución, para poder representar
después un mapa, sobre el cual iremos trabajando:
mapamundo <- getMap(resolution="high")
A continuación vemos los datos que tenemos usando
head:
head(mapamundo)
Y lo visualizamos usando plot:
plot(mapamundo)
FALSE Warning in wkt(obj): CRS object has no comment
FALSE Error : The fig.showtext code chunk option must be TRUE
Como observamos en la imagen se trata de un mapa de todo el mundo, pero a nosotros nos interesa únicamente España, puesto que a los datos descargados podemos acceder como si se tratase de una tabla para quedarnos con España, basta con seleccionar la fila en la que se encuentre el valor de España:
mapaspain <- mapamundo["Spain",]
Podemos incluso seleccionar varios países, por ejemplo, vamos a seleccionar Italia y Francia:
mapaitaliafrancia <- mapamundo[c("Italy", "France"),]
plot(mapaitaliafrancia)
FALSE Warning in wkt(obj): CRS object has no comment
FALSE Error : The fig.showtext code chunk option must be TRUE
Visualizamos el mapa de España:
plot(mapaspain)
FALSE Warning in wkt(obj): CRS object has no comment
FALSE Error : The fig.showtext code chunk option must be TRUE
Como podemos apreciar en la imagen además de la península, nos
muestra las Islas Baleares y Canarias. Vamos a recortar el mapa para
descartar las Islas Canarias, y quedarnos únicamente con la península y
las islas baleares. Para esto vamos a utilizar la función
crop, en donde definiremos un extent con las
coordenadas del área con el que te quieres quedar (un
extent no es más que un rectángulo donde definimos las
latitudes (valores de la x) y longitudes (valores de la
y) mínimas y máximas, en este mismo orden, que definen
el área del mapa que e interesa):
mapaspain <- crop(mapaspain,
extent(-10,
5,
35,
45))
Volvemos a visualizarlo:
plot(mapaspain)
FALSE Warning in wkt(obj): CRS object has no comment
FALSE Error : The fig.showtext code chunk option must be TRUE
Al igual que con cualquier otro plot podemos personalizar nuestro mapa, cambiando por ejemplo el color del polígono y su contorno:
plot(mapaspain,
col="lightblue",
border="white")
FALSE Warning in wkt(obj): CRS object has no comment
FALSE Error : The fig.showtext code chunk option must be TRUE
Por medio del paquete maps podemos generar mapas algo
más completos que los anteriores de forma relativamente sencilla.
Mapa sin fondo
Comenzamos abriendo una ventana para dibujar el mapa usando la
función mapDevice, a continuación usamos la función
mapy definimos varios elementos:
Definimos la zona del mundo de donde queremos que nos descargue el mapa, en nuestro caso descargaremos un mapa del mundo (escogemos la base de datos de donde se descargarán los datos geográficos)
Definimos el color de relleno del polígono
Definimos las coordenadas que queremos que se representen
Escogemos la proyección (en nuestro caso escogemos la proyección albers que es una proyección en metros), la resolución y el color del borde del polígono y su grosor
mapDevice()
map("world",
fill=TRUE,
col="lightblue",
boundary=F,
interior=F,
ylim=c(-60, 65),
mar=c(0,0,0,0),
projection='albers',
par=c(0,0),
wrap=T,
resolution=1,
border="aliceblue",
myborder=0)
FALSE Error : The fig.showtext code chunk option must be TRUE
Mapa con fondo
Podemos añadir un fondo por medio de la función bg,
realizaremos un mapa de Europa y el Norte de África con fondo azul:
map("world",
fill=TRUE,
col="#91849A",
bg="#454973",
boundary=F,
interior=F,
ylim=c(30, 65),
xlim=c(-5,25),
mar=c(0,0,0,0),
projection='albers',
par=c(0,0),
wrap=T,
resolution=0,
border="#D9BBF9",
myborder=0)
FALSE Error : The fig.showtext code chunk option must be TRUE
Podemos utilizar el paquete maps y ggplot
de forma conjunta para generar mapas más personalizados. Primero debemos
generar un capa donde definamos los polígonos que queremos
representar:
mapWorld <- borders("world",
colour="#999DC2",
fill="#575D90",
ylim=c(-60,60),
xlim=c(-180,180))
mapWorld
FALSE mapping: group = ~group, x = ~long, y = ~lat
FALSE geom_polygon: na.rm = FALSE, rule = evenodd
FALSE stat_identity: na.rm = FALSE
FALSE position_identity
A continuación, sobreponemos al mapa anterior una capa de ggplot:
mp <- ggplot() + mapWorld
mp
FALSE Error : The fig.showtext code chunk option must be TRUE
Personalizamos el tema de ggplot:
mp + theme(panel.border = element_blank(),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank())
FALSE Error : The fig.showtext code chunk option must be TRUE
# Primero debemos obtener un mapa, para ello usamos `getMap`:
trymap<-getMap()
# En este mapa podemos generar "burbujas" a las que podemos asociar los datos que queramos:
mapBubbles(dF=trymap,
colourPalette="rainbow",
oceanCol="aliceblue",
landCol="#999DC2",
borderCol="#999DC2",
ylim=c(-49.5,70),
lwd=0.1,
add = T)
FALSE Error in `[.data.frame`(dF, , nameZSize): undefined columns selected
# Y añadimos líneas de contorno:
maps::map("worldHires",
add=T,
col="#BFC1D9",
lwd=1.5)
FALSE Error in plot.xy(xy.coords(x, y), type = type, ...): plot.new has not been called yet
Además de obtener los mapas desde R, podemos obtenerlos directamente desde páginas web y cargar los shapefiles en R. Hemos ido a la siguiente dirección web http://www.naturalearthdata.com/, y desde donde descargamos dos shapefiles:
En el apartado de cultural descargamos el archivo countries de admin0 en escala media
En el apartado de physical descargamos el archivo land
Comenzamos cargado los dos shapefiles gracias a la función
st_read:
land <- st_read("DataScienceUAH-main/ne_50m_land.shp")
FALSE Reading layer `ne_50m_land' from data source
FALSE `C:\Users\tsuba\OneDrive\Escritorio\MANUAL\DataScienceUAH-main\ne_50m_land.shp'
FALSE using driver `ESRI Shapefile'
FALSE Simple feature collection with 1420 features and 3 fields
FALSE Geometry type: MULTIPOLYGON
FALSE Dimension: XY
FALSE Bounding box: xmin: -180 ymin: -89.99893 xmax: 180 ymax: 83.59961
FALSE Geodetic CRS: WGS 84
boundars <- st_read("DataScienceUAH-main/ne_50m_admin_0_countries.shp")
FALSE Reading layer `ne_50m_admin_0_countries' from data source
FALSE `C:\Users\tsuba\OneDrive\Escritorio\MANUAL\DataScienceUAH-main\ne_50m_admin_0_countries.shp'
FALSE using driver `ESRI Shapefile'
FALSE Simple feature collection with 242 features and 161 fields
FALSE Geometry type: MULTIPOLYGON
FALSE Dimension: XY
FALSE Bounding box: xmin: -180 ymin: -89.99893 xmax: 180 ymax: 83.59961
FALSE Geodetic CRS: WGS 84
Representamos gráficamente land:
plot(land)
FALSE Error : The fig.showtext code chunk option must be TRUE
FALSE Error : The fig.showtext code chunk option must be TRUE
FALSE Error : The fig.showtext code chunk option must be TRUE
FALSE Error : The fig.showtext code chunk option must be TRUE
Al ejecutar este código observamos que se generan varios mapas diferentes en función de los atributos del shapefile que hemos descargado. De todos los datos del shapefile solo nos interesa la geometría, que es lo que vamos a dibujar. Además ajustaremos las coordenadas para dibujar únicamente Europa:
plot(land$geometry,
col="grey",
lty=0,ylim=c(30,60),
xlim=c(-5,35))
FALSE Error : The fig.showtext code chunk option must be TRUE
También podemos obtener el mismo mapa pero con las fronteras de los
países al utilizar boundars:
plot(boundars$geometry,
col="grey",
border="white",
ylim=c(30,60),
xlim=c(-5,35))
FALSE Error : The fig.showtext code chunk option must be TRUE
A estos mapas podemos añadir la batimetría (profundidad del fondo
marino), para esto tenemos el paquete marmap. Con el
siguiente comando generamos una capa raster para la batimetría y
escogiendo la región de la que queremos la batimetría por medio de un
extent:
BATHYMET<-getNOAA.bathy(
lon1= 70,
lon2= -45,
lat1= 75,
lat2= 20,
resolution=8)
FALSE Querying NOAA database ...
FALSE This may take seconds to minutes, depending on grid size
FALSE Building bathy matrix ...
Añadir la batimetría a un mapa
Lo primero que debemos hacer es generar una paleta de colores que marque la profundidad del agua, nosotros hemos generado la siguiente paleta:
blues <- c( "#21295C",
"#1B3B6F",
"#065A82",
"#1C7293")
A continuación representamos la batimetría:
plot(BATHYMET,
image = TRUE,
land = TRUE,
lwd = 0.05,
lty=0,
ylim=c(25,70),
xlim=c(-8,35),
bpal = list(c(0, max(BATHYMET), "#1C7293"),
c(min(BATHYMET),0,blues)), add=F)
FALSE Error : The fig.showtext code chunk option must be TRUE
Aquí bpal específica como se aplica la escala de colores
al mapa.
Por encima de la batimetría dibujamos la tierra:
plot(boundars$geometry,
col="#1C7C54",
border="#73E2A7",
ylim=c(30,65),
xlim=c(-8,35),
add=T)
FALSE Error in polypath(p_bind(L), border = border[i], lty = lty[i], lwd = lwd[i], : plot.new has not been called yet
Por medio del paquete hillshade vamos a añadir el
relieve. Vamos a utilizar el mapa que habíamos obtenido al
principio:
mapaspain
FALSE Object of class "SpatialPolygonsDataFrame" (package sp):
FALSE
FALSE Number of SpatialPolygons: 1
FALSE
FALSE Variables measured:
FALSE ne_10m_adm ScaleRank LabelRank FeatureCla OID_ SOVEREIGNT SOV_A3
FALSE Spain ESP 1 2 Adm-0 country 233 Spain ESP
FALSE ADM0_DIF LEVEL TYPE ADMIN ADM0_A3 GEOU_DIF GEOUNIT GU_A3
FALSE Spain 0 2 Sovereign country Spain ESP 0 Spain ESP
FALSE SU_DIF SUBUNIT SU_A3 NAME ABBREV POSTAL NAME_FORMA TERR_ NAME_SORT
FALSE Spain 0 Spain ESP Spain Sp. E Kingdom of Spain <NA> Spain
FALSE MAP_COLOR POP_EST GDP_MD_EST FIPS_10_ ISO_A2 ISO_A3 ISO_N3 ISO3
FALSE Spain 5 40525002 1403000 0 ES ESP 724 ESP
FALSE LON LAT ISO3.1 ADMIN.1 REGION continent GEO3major
FALSE Spain -3.565944 40.40002 ESP Spain Europe Eurasia Europe
FALSE GEO3 IMAGE24 GLOCAF Stern SRESmajor
FALSE Spain Western Europe Western Europe Europe Europe OECD90
FALSE SRES GBD AVOIDnumeric AVOIDname LDC SID
FALSE Spain Western Europe (WEU) Europe, Western 25 Europe other other
FALSE LLDC
FALSE Spain other
En primer lugar vamos a obtener los datos del relieve con
getData, de forma que obtendremos los datos de altura de
España, al poner mask = T conseguimos que nos de solo los
datos de España y que no nos dé datos de los países circundantes.
Posteriormente dibujamos el relieve:
altSpain <- getData('alt',
country='ESP',
mask=T)
plot(altSpain)
FALSE Error : The fig.showtext code chunk option must be TRUE
FALSE Error : The fig.showtext code chunk option must be TRUE
str (altSpain)
FALSE Formal class 'RasterLayer' [package "raster"] with 12 slots
FALSE ..@ file :Formal class '.RasterFile' [package "raster"] with 13 slots
FALSE .. .. ..@ name : chr "C:\\Users\\tsuba\\OneDrive\\Escritorio\\MANUAL\\ESP_msk_alt.grd"
FALSE .. .. ..@ datanotation: chr "INT2S"
FALSE .. .. ..@ byteorder : Named chr "little"
FALSE .. .. .. ..- attr(*, "names")= chr "value"
FALSE .. .. ..@ nodatavalue : num -9999
FALSE .. .. ..@ NAchanged : logi FALSE
FALSE .. .. ..@ nbands : int 1
FALSE .. .. ..@ bandorder : Named chr "BIL"
FALSE .. .. .. ..- attr(*, "names")= chr "value"
FALSE .. .. ..@ offset : int 0
FALSE .. .. ..@ toptobottom : logi TRUE
FALSE .. .. ..@ blockrows : int 0
FALSE .. .. ..@ blockcols : int 0
FALSE .. .. ..@ driver : chr "raster"
FALSE .. .. ..@ open : logi FALSE
FALSE ..@ data :Formal class '.SingleLayerData' [package "raster"] with 13 slots
FALSE .. .. ..@ values : logi(0)
FALSE .. .. ..@ offset : num 0
FALSE .. .. ..@ gain : num 1
FALSE .. .. ..@ inmemory : logi FALSE
FALSE .. .. ..@ fromdisk : logi TRUE
FALSE .. .. ..@ isfactor : logi FALSE
FALSE .. .. ..@ attributes: list()
FALSE .. .. ..@ haveminmax: logi TRUE
FALSE .. .. ..@ min : num -13
FALSE .. .. ..@ max : num 3322
FALSE .. .. ..@ band : int 1
FALSE .. .. ..@ unit : chr ""
FALSE .. .. ..@ names : chr "ESP_msk_alt"
FALSE ..@ legend :Formal class '.RasterLegend' [package "raster"] with 5 slots
FALSE .. .. ..@ type : chr(0)
FALSE .. .. ..@ values : logi(0)
FALSE .. .. ..@ color : logi(0)
FALSE .. .. ..@ names : logi(0)
FALSE .. .. ..@ colortable: logi(0)
FALSE ..@ title : chr(0)
FALSE ..@ extent :Formal class 'Extent' [package "raster"] with 4 slots
FALSE .. .. ..@ xmin: num -9.4
FALSE .. .. ..@ xmax: num 4.4
FALSE .. .. ..@ ymin: num 35.2
FALSE .. .. ..@ ymax: num 43.9
FALSE ..@ rotated : logi FALSE
FALSE ..@ rotation:Formal class '.Rotation' [package "raster"] with 2 slots
FALSE .. .. ..@ geotrans: num(0)
FALSE .. .. ..@ transfun:function ()
FALSE ..@ ncols : int 1656
FALSE ..@ nrows : int 1044
FALSE ..@ crs :Formal class 'CRS' [package "sp"] with 1 slot
FALSE .. .. ..@ projargs: chr "+proj=longlat +datum=WGS84 +no_defs"
FALSE .. .. ..$ comment: chr "GEOGCRS[\"unknown\",\n DATUM[\"World Geodetic System 1984\",\n ELLIPSOID[\"WGS 84\",6378137,298.25722"| __truncated__
FALSE ..@ history : list()
FALSE ..@ z : list()
Al ver la estructura de los datos comprobamos que se trata de un archivo raster que sigue el sistema de coordenadas CRS.
Como no nos agrada la escala de colores que han utilizado vamos a cambiarla:
alt2= altSpain
res(alt2)= 0.02166666 # aquí disminuímos la resolución
Con este código estoy definiendo un nuevo mapa donde utilizo los
datos de altitud de altSpain y reduzco la resolución.
Posteriormente representamos este nuevo mapa:
alt3<-resample(altSpain,
alt2,
method='bilinear')
plot(alt3)
FALSE Error : The fig.showtext code chunk option must be TRUE
FALSE Error : The fig.showtext code chunk option must be TRUE
Sobre este mapa donde muestra el gradiente de alturas añadiremos la pendiente, el aspecto del terreno y el sombreado de las colinas:
slope <- terrain(alt3, opt='slope') # mapa de pendientes
aspect <- terrain(alt3, opt='aspect') # mapa de aspecto
hill <- hillShade(slope, aspect, 30, 250, normalize=T) # sombreado de colinas
Finalmente cambiamos el color, podríamos añadirle color generando una nueva capa, pero para que no se perdiese la forma del relieve tendríamos que darle transparencia:
plot(hill,
col=adjustcolor(grey(0:100/100),0.8),
legend=FALSE,
add=F)
FALSE Error : The fig.showtext code chunk option must be TRUE
lines(Spain,lwd=1.5)
FALSE Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'lines': object 'Spain' not found
Así conseguimos el aspecto del relieve del mapa.
En este ejemplo vamos a trabajar con los datos del censo de las poblaciones españolas.
Primero cargamos datos del censo de población del INE, que viene
disponible por defecto en el paquete mapSpain, cargaremos
datos de la población mundial del año 2019:
census <- pobmun19
A continuación, vamos a descargar y guardar el código de las
comunidades autónomas, usando otra vez el paquete mapSpain,
y veremos su estructura con str:
codelist <- esp_codelist
str(codelist)
FALSE 'data.frame': 59 obs. of 44 variables:
FALSE $ nuts1.code : chr "ES1" "ES1" "ES1" "ES1" ...
FALSE $ nuts1.name : chr "NOROESTE" "NOROESTE" "NOROESTE" "NOROESTE" ...
FALSE $ nuts1.name.alt : chr "Noroeste" "Noroeste" "Noroeste" "Noroeste" ...
FALSE $ nuts1.shortname.es: chr "Noroeste" "Noroeste" "Noroeste" "Noroeste" ...
FALSE $ codauto : chr "03" "06" "12" "12" ...
FALSE $ iso2.ccaa.code : chr "ES-AS" "ES-CB" "ES-GA" "ES-GA" ...
FALSE $ nuts2.code : chr "ES12" "ES13" "ES11" "ES11" ...
FALSE $ ine.ccaa.name : chr "Asturias, Principado de" "Cantabria" "Galicia" "Galicia" ...
FALSE $ iso2.ccaa.name.es : chr "Asturias, Principado de" "Cantabria" "Galicia" "Galicia" ...
FALSE $ iso2.ccaa.name.ca : chr NA NA NA NA ...
FALSE $ iso2.ccaa.name.gl : chr NA NA "Galicia" "Galicia" ...
FALSE $ iso2.ccaa.name.eu : chr NA NA NA NA ...
FALSE $ nuts2.name : chr "Principado de Asturias" "Cantabria" "Galicia" "Galicia" ...
FALSE $ cldr.ccaa.name.en : chr "Asturias" "Cantabria" "Galicia" "Galicia" ...
FALSE $ cldr.ccaa.name.es : chr "Principado de Asturias" "Cantabria" "Galicia" "Galicia" ...
FALSE $ cldr.ccaa.name.ca : chr "Astúries" "Cantàbria" "Galícia" "Galícia" ...
FALSE $ cldr.ccaa.name.ga : chr "Principado de Asturias" "Cantabria" "Galicia" "Galicia" ...
FALSE $ cldr.ccaa.name.eu : chr "Asturiesko Printzerria" "Kantabria" "Galizia" "Galizia" ...
FALSE $ ccaa.shortname.en : chr "Asturias" "Cantabria" "Galicia" "Galicia" ...
FALSE $ ccaa.shortname.es : chr "Asturias" "Cantabria" "Galicia" "Galicia" ...
FALSE $ ccaa.shortname.ca : chr "Astúries" "Cantàbria" "Galícia" "Galícia" ...
FALSE $ ccaa.shortname.ga : chr "Asturias" "Cantabria" "Galicia" "Galicia" ...
FALSE $ ccaa.shortname.eu : chr "Asturias" "Kantabria" "Galizia" "Galizia" ...
FALSE $ cpro : chr "33" "39" "15" "27" ...
FALSE $ iso2.prov.code : chr "ES-O" "ES-S" "ES-C" "ES-LU" ...
FALSE $ nuts.prov.code : chr "ES120" "ES130" "ES111" "ES112" ...
FALSE $ ine.prov.name : chr "Asturias" "Cantabria" "Coruña, A" "Lugo" ...
FALSE $ iso2.prov.name.es : chr "Asturias" "Cantabria" "La Coruña" "Lugo" ...
FALSE $ iso2.prov.name.ca : chr NA NA NA NA ...
FALSE $ iso2.prov.name.ga : chr NA NA "A Coruña" "Lugo" ...
FALSE $ iso2.prov.name.eu : chr NA NA NA NA ...
FALSE $ cldr.prov.name.en : chr "Asturias" "Cantabria" "A Coruña" "Lugo" ...
FALSE $ cldr.prov.name.es : chr "Principado de Asturias" "Cantabria" "Provincia de La Coruña" "Provincia de Lugo" ...
FALSE $ cldr.prov.name.ca : chr "Astúries" "Cantàbria" "Província de la Corunya" "Província de Lugo" ...
FALSE $ cldr.prov.name.ga : chr "Principado de Asturias" "Cantabria" "Provincia da Coruña" "Provincia de Lugo" ...
FALSE $ cldr.prov.name.eu : chr "Asturiesko Printzerria" "Kantabria" "Coruñako probintzia" "Lugoko probintzia" ...
FALSE $ prov.shortname.en : chr "Asturias" "Cantabria" "A Coruña" "Lugo" ...
FALSE $ prov.shortname.es : chr "Asturias" "Cantabria" "La Coruña" "Lugo" ...
FALSE $ prov.shortname.ca : chr "Astúries" "Cantàbria" "La Corunya" "Lugo" ...
FALSE $ prov.shortname.ga : chr "Asturias" "Cantabria" "A Coruña" "Lugo" ...
FALSE $ prov.shortname.eu : chr "Asturias" "Kantabria" "Coruña" "Lugo" ...
FALSE $ nuts3.code : chr "ES120" "ES130" "ES111" "ES112" ...
FALSE $ nuts3.name : chr "Asturias" "Cantabria" "A Coruña" "Lugo" ...
FALSE $ nuts3.shortname.es: chr "Asturias" "Cantabria" "La Coruña" "Lugo" ...
Como podemos observar, codelist contiene un listado de
todas las localidades de España y de todas las comunidades
autónomas.
Ahora unimos las dos tablas utilizando el comando
merge:
census <-
unique(merge(census, codelist[, c("cpro", "codauto")], all.x = TRUE))
Agregamos los valores por comunidad autónoma:
census_ccaa <-
aggregate(cbind(pob19, men, women) ~ codauto, data = census, sum)
Calculamos porcentajes y los guardamos como nuevas variables en nuestro dataframe añadimos una variable donde el porcentaje se represente con respecto a 100 en vez de con respecto a 1, añadiendo a la vez el símbolo % detrás del número por motivos estéticos:
En mujeres:
census_ccaa$porc_women <- census_ccaa$women / census_ccaa$pob19
census_ccaa$porc_women_lab <-
paste0(round(100 * census_ccaa$porc_women, 2),"%")
En hombres:
census_ccaa$porc_men <- census_ccaa$men / census_ccaa$pob19
census_ccaa$porc_men_lab <-
paste0(round(100 * census_ccaa$porc_men, 2), "%")
Observamos que se nos han creado las variables correspondientes:
head(census_ccaa)
Queremos representar estos porcentajes en un mapa, para ello vamos a
unir nuestro dataframe con un shapefile donde se representen todas las
comunidades autónomas de España para ello seguimos usando la librería
mapSpain:
# Obtenemos el shapefile
CCAA_sf <- esp_get_ccaa()
plot(CCAA_sf$geometry)
FALSE Error : The fig.showtext code chunk option must be TRUE
# El shapefile incluye canarias de la misma manera como se representan en los atlas
# Unimos nuestro dataframe con el shapefile usando `merge`
CCAA_sf <- merge(CCAA_sf, census_ccaa)
# Recuadramos las isla canarias para que quede más bonito
Can <- esp_get_can_box()
plot(Can, add=T)
La representación de este mapa también la podemos realizar con
ggplot, utilizando geom_sf para representar shapefiles:
ggplot(CCAA_sf) +
geom_sf(aes(fill = porc_women),
color = "grey70",
lwd = .3
) +
geom_sf(data = Can, color = "grey70") + # añadimos el recuadro de Canarias
geom_sf_label(aes(label = porc_women_lab), # añadimos las etiquetas de porcentajes
fill = "white", alpha = 0.5,
size = 3,
label.size = 0
) +
scale_fill_gradientn(
colors = hcl.colors(10, "Blues", rev = TRUE), # cambiamos la escala de colores
n.breaks = 10,
labels = function(x) {
sprintf("%1.1f%%", 100 * x)
},
guide = guide_legend(title = "Porc. women") # añadimos la leyenda
) +
theme_void() + # utilizamos un tema para que quede más bonito
theme(legend.position = "right") # cambiamos la posición de la leyenda
FALSE Error : The fig.showtext code chunk option must be TRUE
FALSE Warning in st_point_on_surface.sfc(sf::st_zm(x)): st_point_on_surface may not
FALSE give correct results for longitude/latitude data
Primero añadimos el porcentaje de mujeres a la tabla census:
census$porc_women <- census$women / census$pob19
census$porc_men <- census$men / census$pob19
Obtenemos capas shapefile de municipios y provincias, vamos a representar Ávila:
shape <- esp_get_munic_siane(region = "Avila", epsg = 3857)
provs <- esp_get_prov_siane(epsg = 3857)
Representamos para ver que aspecto tiene y exploramos las variables:
plot(shape$geometry) # Mapa de Ávila por municipios
FALSE Error : The fig.showtext code chunk option must be TRUE
plot(provs$geometry) # Mapa de España por provincias
FALSE Error : The fig.showtext code chunk option must be TRUE
head(shape)
head(census)
Unimos datos a escala de municipio con el comando merge
y representamos:
shape_pop <- merge(shape,census,
by = c("cpro", "cmun"),
all.x = TRUE)
plot(shape_pop$geometry)
FALSE Error : The fig.showtext code chunk option must be TRUE
Obtenemos información raster para el fondo del mapa y representamos:
tile <- esp_getTiles(shape_pop,
type = "IGNBase.Todo",
zoom = 10,
bbox_expand = .1)
plot(tile) # la imagen incluye las carreteras, relieves, etc de Ávila
FALSE Error : The fig.showtext code chunk option must be TRUE
Dibujamos el mapa completo:
# Obtenemos el extent (es decir, los limites de Ávila) geográfico con
# la función ext del paquete `terra`
lims <- as.double(terra::ext(tile)@ptr$vector)
# Dibujamos con ggplot
ggplot(remove_missing(shape_pop, na.rm = TRUE)) +
layer_spatraster(tile) +
geom_sf(aes(fill = porc_women), color = NA) +
geom_sf(data = provs, fill = NA) +
scale_fill_gradientn(
colours = hcl.colors(10, "RdYlBu", alpha = .4),
n.breaks = 8,
labels = function(x) {
sprintf("%1.0f%%", 100 * x)
},
guide = guide_legend(title = "", )
) +
coord_sf(
xlim = lims[c(1, 2)],
ylim = lims[c(3, 4)],
expand = FALSE
) +
labs(
title = "Proporción de mujeres en Ávila por municipio (2019)",
caption = "Source: INE"
) +
theme_void() +
theme(
title = element_text(face = "bold")
)
FALSE Error : The fig.showtext code chunk option must be TRUE
Con el paquete mapSpain obtenemos las cuencas
hidrográficas:
hydroland <- esp_get_hydrobasin(domain = "land")
hydrolandsea <- esp_get_hydrobasin(domain = "landsea")
plot(hydroland$geom)
FALSE Error : The fig.showtext code chunk option must be TRUE
ggplot(hydroland) +
geom_sf(data = hydrolandsea, fill = "#C6E0FF", alpha = .4) +
geom_sf(fill = "#C6E0FF", alpha = .5, color= "#42858C") +
geom_sf_text(aes(label = rotulo),
size = 3, check_overlap = TRUE,
fontface = "bold",
family = "sans"
) +
coord_sf(
xlim = c(-9.5, 4.5),
ylim = c(35, 44)
) +
theme_void()
FALSE Error : The fig.showtext code chunk option must be TRUE
FALSE Warning in st_point_on_surface.sfc(sf::st_zm(x)): st_point_on_surface may not
FALSE give correct results for longitude/latitude data
Así hemos representado todas las cuencas hidrográficas de España, exceptuando Canarias
Descargamos datos de batimetría y altimetría utilizando
mapSpain:
hypsobath <- esp_get_hypsobath()
Hay que corregir un error en los datos de origen y usamos
Remove:
hypsobath <- hypsobath[!sf::st_is_empty(hypsobath), ]
En la representación gráfica emplearemos los colores utilizados en los atlas, los cuales hemos obtenido a través de wikipedia en el siguiente enlace: https://en.wikipedia.org/wiki/Wikipedia:WikiProject_Maps/Conventions/Topographic_maps
Establecemos las paletas de colores:
# Para la batimetría
bath_tints <- colorRampPalette(
rev(
c(
"#D8F2FE", "#C6ECFF", "#B9E3FF",
"#ACDBFB", "#A1D2F7", "#96C9F0",
"#8DC1EA", "#84B9E3", "#79B2DE",
"#71ABD8"
)
)
)
# Para la altitud
hyps_tints <- colorRampPalette(
rev(
c(
"#F5F4F2", "#E0DED8", "#CAC3B8", "#BAAE9A",
"#AC9A7C", "#AA8753", "#B9985A", "#C3A76B",
"#CAB982", "#D3CA9D", "#DED6A3", "#E8E1B6",
"#EFEBC0", "#E1E4B5", "#D1D7AB", "#BDCC96",
"#A8C68F", "#94BF8B", "#ACD0A5"
)
)
)
Ordenamos en nuestro dataframe los niveles de altura para nos coloree de menor altura a mayor altura siguiendo la paleta de colores que hemos definido:
levels <- sort(unique(hypsobath$val_inf))
Establecemos los parametros de la paleta:
br_bath <- length(levels[levels < 0])
br_terrain <- length(levels) - br_bath
pal <- c(bath_tints((br_bath)), hyps_tints((br_terrain)))
Hacemos la representación para las islas Canarias:
ggplot(hypsobath) +
geom_sf(aes(fill = as.factor(val_inf)),
color = NA
) +
coord_sf(
xlim = c(-18.6, -13),
ylim = c(27, 29.5)
) +
scale_fill_manual(values = pal) +
guides(fill = guide_legend(
title = "Elevation",
direction = "horizontal",
label.position = "bottom",
title.position = "top",
nrow = 1
)) +
theme(legend.position = "bottom")
FALSE Error : The fig.showtext code chunk option must be TRUE
Representamos para la Península y Baleares:
spainhypbat <- ggplot(hypsobath) +
geom_sf(aes(fill = as.factor(val_inf)),
color = NA
) +
coord_sf(
xlim = c(-9.5, 4.4),
ylim = c(35.8, 44)
) +
scale_fill_manual(values = pal) +
guides(fill = guide_legend(
title = "Elevation",
reverse = TRUE,
keyheight = .8
))
spainhypbat
FALSE Error : The fig.showtext code chunk option must be TRUE
Podemos querer trabajar con distribuciones de especies, una forma rápida de obtener estos datos con R es a partir de GBIF.
GBIF es una red online donde se permite el acceso libre y abierto a información de la biodiversidad de países y regiones del todo el mundo para la investigación científica. Lo más interesante es que ahora se puede acceder a está red desde R, facilitando aún más la obtención de datos.
Vamos a extraer datos de la distribución y presencia para el lince ibérico (Lynx pardinus)
lynx <- gbif("Lynx", "pardinus") # hacemos una búqueda en GBIF
FALSE 1316 records found
FALSE 0-300-600-900-1200-1316 records downloaded
lynx